import { and, eq } from 'drizzle-orm';
import { NextRequest, NextResponse } from 'next/server';
import { trainingMatrices } from '@/db/schema';
import type { TrainingMatrixMutationPayload } from '@/features/training-matrix/api/types';
import {
  canManageTrainingMatrix,
  getTrainingMatrixByIdForOrganization,
  normalizeTrainingMatrixPayload,
  serializeTrainingMatrix
} from '@/features/training-matrix/server/training-matrix-data';
import { AuthError, requireOrganizationAccess } from '@/lib/auth/session';
import { db } from '@/lib/db';

type Params = { params: Promise<{ id: string }> };

export async function GET(request: NextRequest, { params }: Params) {
  try {
    const { organization, membership } = await requireOrganizationAccess();

    if (!canManageTrainingMatrix(membership.role)) {
      return NextResponse.json({ message: 'Forbidden' }, { status: 403 });
    }

    const { id } = await params;
    const matrix = await getTrainingMatrixByIdForOrganization({
      id: Number(id),
      organizationId: organization.id
    });

    if (!matrix) {
      return NextResponse.json(
        { success: false, message: `Training matrix with ID ${id} not found` },
        { status: 404 }
      );
    }

    return NextResponse.json({
      success: true,
      time: new Date().toISOString(),
      message: `Training matrix with ID ${id} found`,
      training_matrix: serializeTrainingMatrix(matrix)
    });
  } catch (error) {
    if (error instanceof AuthError) {
      return NextResponse.json({ message: error.message }, { status: error.status });
    }

    return NextResponse.json({ message: 'Unable to load training matrix' }, { status: 500 });
  }
}

export async function PATCH(request: NextRequest, { params }: Params) {
  try {
    const { organization, membership } = await requireOrganizationAccess();

    if (!canManageTrainingMatrix(membership.role)) {
      return NextResponse.json({ message: 'Forbidden' }, { status: 403 });
    }

    const { id } = await params;
    const body = normalizeTrainingMatrixPayload(
      (await request.json()) as TrainingMatrixMutationPayload
    );

    const existingMatrix = await getTrainingMatrixByIdForOrganization({
      id: Number(id),
      organizationId: organization.id
    });

    if (!existingMatrix) {
      return NextResponse.json(
        { success: false, message: `Training matrix with ID ${id} not found` },
        { status: 404 }
      );
    }

    const [matrix] = await db
      .update(trainingMatrices)
      .set({
        departmentId: body.departmentId,
        positionId: body.positionId,
        courseId: body.courseId,
        isRequired: body.isRequired,
        renewalPeriodMonths: body.renewalPeriodMonths,
        note: body.note,
        updatedAt: new Date()
      })
      .where(
        and(eq(trainingMatrices.id, Number(id)), eq(trainingMatrices.organizationId, organization.id))
      )
      .returning();

    const updatedMatrix = await getTrainingMatrixByIdForOrganization({
      id: matrix.id,
      organizationId: organization.id
    });

    return NextResponse.json({
      success: true,
      time: new Date().toISOString(),
      message: 'Training matrix updated successfully',
      training_matrix: updatedMatrix
        ? serializeTrainingMatrix(updatedMatrix)
        : serializeTrainingMatrix({
            id: matrix.id,
            organizationId: matrix.organizationId,
            departmentId: matrix.departmentId,
            departmentName: existingMatrix.departmentName,
            positionId: matrix.positionId,
            positionName: existingMatrix.positionName,
            courseId: matrix.courseId,
            courseName: existingMatrix.courseName,
            courseCategory: existingMatrix.courseCategory,
            courseCertificateValidityMonths: existingMatrix.courseCertificateValidityMonths,
            isRequired: matrix.isRequired,
            renewalPeriodMonths: matrix.renewalPeriodMonths,
            note: matrix.note,
            createdAt: matrix.createdAt,
            updatedAt: matrix.updatedAt
          })
    });
  } catch (error) {
    if (error instanceof AuthError) {
      return NextResponse.json({ message: error.message }, { status: error.status });
    }

    return NextResponse.json({ message: 'Unable to update training matrix' }, { status: 500 });
  }
}

export async function DELETE(request: NextRequest, { params }: Params) {
  try {
    const { organization, membership } = await requireOrganizationAccess();

    if (!canManageTrainingMatrix(membership.role)) {
      return NextResponse.json({ message: 'Forbidden' }, { status: 403 });
    }

    const { id } = await params;
    const [deletedMatrix] = await db
      .delete(trainingMatrices)
      .where(
        and(eq(trainingMatrices.id, Number(id)), eq(trainingMatrices.organizationId, organization.id))
      )
      .returning({ id: trainingMatrices.id });

    if (!deletedMatrix) {
      return NextResponse.json(
        { success: false, message: `Training matrix with ID ${id} not found` },
        { status: 404 }
      );
    }

    return NextResponse.json({
      success: true,
      message: 'Training matrix deleted successfully'
    });
  } catch (error) {
    if (error instanceof AuthError) {
      return NextResponse.json({ message: error.message }, { status: error.status });
    }

    return NextResponse.json({ message: 'Unable to delete training matrix' }, { status: 500 });
  }
}
