import { getSession } from '@/lib/auth';
import { db } from '@/lib/db';
import { createResponse, handleApiError } from '@/src/lib/api';
import { PortfolioContributorStatus } from '@prisma/client';
import { NextRequest } from 'next/server';
import { randomBytes } from 'crypto';
import { EmailService } from '@/src/services/EmailService';

export async function GET(req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
  try {
    const session = await getSession();

    const { id } = await params;
    const portfolio = await db.portfolio.findUnique({
      where: {
        id,
      },
      include: {
        PortfolioProject: {
          include: {
            Project: true,
          },
        },
        invitations: {
          where: {
            acceptedAt: null,
          },
          select: {
            email: true,
          }
        },
        PortfolioContributor: {
          select: {
            userId: true,
            status: true,
            User: {
              select: {
                email: true,
                username: true,
              },
            },
          },
          where: {
            status: {
              not: PortfolioContributorStatus.REJECTED,
            },
          },
        },
      },
    });

    if (!portfolio) {
      return createResponse(404, 'Portfolio not found');
    }

    const isAdmin = session?.user?.role === 'ADMIN';
    const isOwner = portfolio.ownerId === session?.user?.id;
    const isContributor = portfolio.PortfolioContributor.some(
      (contributor) =>
        contributor.userId === session?.user?.id && contributor.status === PortfolioContributorStatus.APPROVED
    );

    if (!isAdmin && !isOwner && !isContributor) {
      return createResponse(401, 'Unauthorized');
    }

    const portfolioResponse = {
      ...portfolio,
      contributors: [
        ...portfolio.PortfolioContributor.map((contributor) => ({
          id: contributor.userId,
          status: contributor.status,
          email: contributor.User.email,
          username: contributor.User.username,
        })),
        ...portfolio.invitations.map((invitation) => ({
          id: '',
          status: 'PENDING',
          email: invitation.email,
          username: '',
        })),
      ],
    };

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

// Update a portfolio by ID
export async function PATCH(req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
  try {
    const session = await getSession();
    let url = null;
    const { id } = await params;
    const { title, contributors, is_published } = await req.json();

    const portfolio = await db.portfolio.findUnique({
      where: {
        id,
      },
    });

    if (!portfolio) {
      return createResponse(404, 'Portfolio not found');
    }

    if (is_published) {
      const owner = await db.user.findUnique({
        where: { id: portfolio.ownerId },
        select: { username: true },
      });
      url = `${owner?.username}/${portfolio.title}`;
    }

    if (session?.user?.role === 'ADMIN') {
      const updated = await db.portfolio.update({
        where: { id },
        data: { title, is_published, url },
      });
    
      return createResponse(200, 'Portfolio updated', {
        portfolio: updated,
      });
    }

    if (portfolio.ownerId !== session?.user?.id) {
      return createResponse(401, 'Unauthorized');
    }

    const updatedPortfolio = await db.$transaction(async (tx) => {
      const updated = await tx.portfolio.update({
        where: { id },
        data: { title, is_published, url },
      });
    
      if (contributors) {
        const existingContributors = await tx.portfolioContributor.findMany({
          where: { portfolioId: id },
          select: { userId: true },
        });
    
        const existingInvitations = await tx.invitation.findMany({
          where: { portfolioId: id },
          select: { email: true },
        });

        const existingUsers = await tx.user.findMany({
          where: {
            email: {
              in: contributors.map((c: { email: string }) => c.email)
            }
          },
          select: {
            id: true,
            email: true
          }
        });
    
        const newInvitations = contributors.filter((c: { email: string }) => 
          !existingUsers.some(user => user.email === c.email)
        );
    
        const newContributors = existingUsers.filter(
          (contributor: { id: string }) =>
            !existingContributors.some((existing) => existing.userId === contributor.id)
        );
    
        const contributorsToDelete = existingContributors.filter(
          (existing: { userId: string }) =>
            !existingUsers.some((contributor: { id: string }) => contributor.id === existing.userId)
        );
    
        const existingContributorsIds = existingContributors.map((c) => c.userId);

      
        await tx.portfolioContributor.updateMany({
          where: {
            userId: {
              in: existingContributorsIds,
            },
            portfolioId: id,
          },
          data: {
            status: PortfolioContributorStatus.PENDING,
          },
        });
    
        await tx.portfolioContributor.createMany({
          data: newContributors.map((c: { id: string }) => ({
            portfolioId: id,
            userId: c.id,
            status: PortfolioContributorStatus.PENDING,
          })),
        });
    
        await tx.portfolioContributor.deleteMany({
          where: {
            portfolioId: id,
            userId: {
              in: contributorsToDelete.map((c) => c.userId),
            },
          },
        });
    
        const newInvitationEmails = newInvitations
          .map((c: { email: string }) => c.email)
          .filter((email: string) => !existingInvitations.some(inv => inv.email === email));
    
        const invitationsToDelete = existingInvitations.filter(
          existing => !contributors.some((c: { email: string }) => c.email === existing.email)
        );
    
        await tx.invitation.deleteMany({
          where: {
            portfolioId: id,
            email: {
              in: invitationsToDelete.map(inv => inv.email),
            },
          },
        });
    
        if (newInvitationEmails.length > 0) {
          await tx.invitation.createMany({
            data: newInvitationEmails.map((email: string) => ({
              email,
              portfolioId: id,
              token: randomBytes(32).toString('hex'),
            })),
          });
    
          const newInvitations = await tx.invitation.findMany({
            where: {
              portfolioId: id,
              email: {
                in: newInvitationEmails,
              },
            },
          });
    
          await EmailService.sendInvitations(
            newInvitations,
            updated.title,
            session?.user?.username
          );
        }
      }
    
      return updated;
    });
    return createResponse(200, 'Portfolio updated', {
      data: updatedPortfolio,
    });
  } catch (error) {
    return handleApiError(error);
  }
}

export async function DELETE(req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
  try {
    const session = await getSession();

    const { id } = await params;
    const portfolio = await db.portfolio.findUnique({
      where: { id },
    });

    if (!portfolio) {
      return createResponse(404, 'Portfolio not found');
    }

    if (session?.user?.role === 'ADMIN' || portfolio.ownerId === session?.user?.id) {
      await db.portfolio.delete({
        where: { id },
      });
      return createResponse(200, `Portfolio ${portfolio.title} deleted`);
    }

    return createResponse(401, 'Unauthorized');
  } catch (error) {
    return handleApiError(error);
  }
}
