import { db } from '@/lib/db';
import { createResponse, handleApiError, PAGE_SIZE } from '@/src/lib/api';
import { NextRequest } from 'next/server';
import { getSession } from '@/lib/auth';
import { Portfolio, PortfolioContributorStatus, Prisma, PortfolioProjectStatus } from '@prisma/client';
import { randomBytes } from 'crypto';
import { EmailService } from '@/src/services/EmailService';
type PortfolioWithRelations = Portfolio & {
  User: { username: string };
  PortfolioContributor: { status: PortfolioContributorStatus }[];
  PortfolioProject: { status: PortfolioProjectStatus }[];
};

export async function GET(req: NextRequest) {
  try {
    const session = await getSession();
    const search = new URL(req.url).searchParams.get('search') ?? '';
    const page = parseInt(new URL(req.url).searchParams.get('page') ?? '1');
    const isAdmin = session?.user?.role === 'ADMIN';

    const baseWhere: Prisma.PortfolioWhereInput = {
      title: {
        contains: search,
        mode: 'insensitive',
      },
    };

    if (!isAdmin) {
      baseWhere.OR = [
        { ownerId: session?.user?.id },
        {
          PortfolioContributor: {
            some: {
              userId: session?.user?.id,
              status: { not: PortfolioContributorStatus.REJECTED },
            },
          },
        },
      ];
    }

    const [portfolios, totalPortfolios] = await db.$transaction([
      db.portfolio.findMany({
        where: baseWhere,
        skip: isAdmin ? (page - 1) * PAGE_SIZE : undefined,
        take: isAdmin ? PAGE_SIZE : undefined,
        include: {
          PortfolioProject: {
            where: {
              status: 'PENDING'
            },
            select: {
              status: true,
            },
          },
          User: {
            select: { username: true },
          },
          ...(isAdmin
            ? {}
            : {
                PortfolioContributor: {
                  where: { userId: session?.user?.id },
                  select: { status: true },
                  take: 1,
                },
              }),
        },
        orderBy: [{ updatedAt: 'desc' }],
      }),
      db.portfolio.count({ where: baseWhere }),
    ]);

    const transformedPortfolios = !isAdmin
      ? (portfolios as PortfolioWithRelations[])
          .map((portfolio) => {
            const isOwner = portfolio.ownerId === session?.user?.id;
            return {
              ...portfolio,
              role: isOwner ? 'Owner' : 'Contributor',
              status: isOwner ? PortfolioContributorStatus.APPROVED : portfolio.PortfolioContributor[0]?.status || null,
              pendingProjects: portfolio.PortfolioProject.length,
              PortfolioProject: undefined,
              contributors: undefined,
              owner: portfolio.User.username,
            };
          })
          .sort((a, b) => {
            const aIsPending = a.status === PortfolioContributorStatus.PENDING ? 1 : 0;
            const bIsPending = b.status === PortfolioContributorStatus.PENDING ? 1 : 0;
            return bIsPending - aIsPending;
          })
      : portfolios.map((portfolio) => ({
          ...portfolio,
          owner: portfolio.User.username,
          pendingProjects: portfolio.PortfolioProject.length,
          PortfolioProject: undefined,
        }));

    return createResponse(200, 'Portfolios retrieved', {
      data: transformedPortfolios,
      pagination: {
        page,
        total: totalPortfolios,
        totalPages: Math.ceil(totalPortfolios / PAGE_SIZE),
      },
    });
  } catch (error) {
    return handleApiError(error);
  }
}

export async function POST(req: NextRequest) {
  try {
    const session = await getSession();

    const { title, contributors } = await req.json();

    const existingUsers = await db.user.findMany({
      where: {
        email: {
          in: contributors.map((contributor: { email: string }) => contributor.email),
        },
      },
    });

    const newUsers = contributors.filter((contributor: { email: string }) => !existingUsers.some((user) => user.email === contributor.email));

    const portfolio = await db.$transaction(async () => {
      const portfolio = await db.portfolio.create({
        data: {
          title: title.toLowerCase(),
          User: {
            connect: {
              id: session?.user?.id,
            },
          },
        },
      });

      await db.portfolioContributor.createMany({
        data: existingUsers.map((contributor: { id: string }) => ({
          portfolioId: portfolio.id,
          userId: contributor.id,
        })),
      });

      await db.invitation.createMany({
        data: newUsers.map((contributor: { email: string }) => ({
          email: contributor.email,
          portfolioId: portfolio.id,
          token: randomBytes(32).toString('hex'),
        })),
      });

      const invitations = await db.invitation.findMany({
        where: {
          portfolioId: portfolio.id,
          email: {
            in: newUsers.map((user: { email: string }) => user.email)
          }
        }
      });

      await EmailService.sendInvitations(invitations, portfolio.title, session?.user?.username);
      
      return portfolio;
    });

    return createResponse(200, 'Portfolio created', {
      data: portfolio,
    });
  } catch (error) {
    return handleApiError(error);
  }
}
