import { and, eq, inArray, ne } from 'drizzle-orm';
import { NextRequest, NextResponse } from 'next/server';
import { departments, memberships, organizations, positions, users } from '@/db/schema';
import {
  AUDIT_ACTION,
  AUDIT_MODULE,
  getRequestMetadata,
  logAuditEvent,
  toAuditValue
} from '@/features/audit-logs/server/audit-service';
import { createMasterReviewNotification } from '@/features/notifications/server/notification-service';
import { AuthError, requireHRD } from '@/lib/auth/session';
import { db } from '@/lib/db';

async function getOrganizationUserIds(organizationId: string) {
  const rows = await db
    .select({ id: memberships.userId })
    .from(memberships)
    .where(eq(memberships.organizationId, organizationId));

  return rows.map((row) => row.id);
}

async function updateOrganizationPendingCompanyFlag(organizationId: string, organizationName: string) {
  const [remaining] = await db
    .selectDistinct({ id: users.companyName })
    .from(memberships)
    .innerJoin(users, eq(memberships.userId, users.id))
    .where(and(eq(memberships.organizationId, organizationId), ne(users.companyName, organizationName)));

  await db
    .update(organizations)
    .set({
      pendingMasterReview: Boolean(remaining),
      updatedAt: new Date()
    })
    .where(eq(organizations.id, organizationId));
}

export async function GET() {
  try {
    const { organization } = await requireHRD();

    const [companyRows, departmentRows, positionRows] = await Promise.all([
      db
        .selectDistinct({
          id: users.companyName,
          name: users.companyName
        })
        .from(memberships)
        .innerJoin(users, eq(memberships.userId, users.id))
        .where(and(eq(memberships.organizationId, organization.id), ne(users.companyName, organization.name))),
      db
        .select()
        .from(departments)
        .where(and(eq(departments.organizationId, organization.id), eq(departments.pendingMasterReview, true))),
      db
        .select()
        .from(positions)
        .where(and(eq(positions.organizationId, organization.id), eq(positions.pendingMasterReview, true)))
    ]);

    const companies = await Promise.all(
      companyRows
        .filter((row) => row.id && row.name)
        .map(async (row) => {
          const affectedRows = await db
            .select({ value: users.id })
            .from(memberships)
            .innerJoin(users, eq(memberships.userId, users.id))
            .where(and(eq(memberships.organizationId, organization.id), eq(users.companyName, row.name!)));

          return {
            id: row.id!,
            type: 'company' as const,
            name: row.name!,
            affected_count: affectedRows.length,
            status: 'pending' as const
          };
        })
    );

    const departmentsPayload = await Promise.all(
      departmentRows.map(async (row) => {
        const affectedRows = await db
          .select({ value: users.id })
          .from(memberships)
          .innerJoin(users, eq(memberships.userId, users.id))
          .where(and(eq(memberships.organizationId, organization.id), eq(users.departmentId, row.id)));

        return {
          id: String(row.id),
          type: 'department' as const,
          name: row.name,
          affected_count: affectedRows.length,
          status: 'pending' as const
        };
      })
    );

    const positionsPayload = await Promise.all(
      positionRows.map(async (row) => {
        const affectedRows = await db
          .select({ value: users.id })
          .from(memberships)
          .innerJoin(users, eq(memberships.userId, users.id))
          .where(and(eq(memberships.organizationId, organization.id), eq(users.positionId, row.id)));

        return {
          id: String(row.id),
          type: 'position' as const,
          name: row.name,
          affected_count: affectedRows.length,
          status: 'pending' as const
        };
      })
    );

    return NextResponse.json({
      success: true,
      message: 'โหลดรายการรอตรวจสอบข้อมูลหลักเรียบร้อยแล้ว',
      companies,
      departments: departmentsPayload,
      positions: positionsPayload
    });
  } catch (error) {
    if (error instanceof AuthError) {
      return NextResponse.json({ message: error.message }, { status: error.status });
    }

    return NextResponse.json({ message: 'ไม่สามารถโหลดรายการรอตรวจสอบได้' }, { status: 500 });
  }
}

export async function PATCH(request: NextRequest) {
  try {
    const { organization, session } = await requireHRD();
    const requestMetadata = getRequestMetadata(request);
    const body = (await request.json()) as {
      entityType: 'company' | 'department' | 'position';
      action: 'approve' | 'reject';
      id: string;
    };

    const scopedUserIds = await getOrganizationUserIds(organization.id);

    if (body.entityType === 'company') {
      if (body.action === 'approve') {
        await db
          .update(organizations)
          .set({
            name: body.id,
            updatedAt: new Date()
          })
          .where(eq(organizations.id, organization.id));

        await updateOrganizationPendingCompanyFlag(organization.id, body.id);

        await createMasterReviewNotification({
          organizationId: organization.id,
          userId: session.user.id,
          masterType: 'บริษัท',
          entityName: body.id,
          action: 'approve',
          referenceId: body.id
        });

        await logAuditEvent({
          organizationId: organization.id,
          userId: session.user.id,
          module: AUDIT_MODULE.MASTER_REVIEW,
          action: AUDIT_ACTION.APPROVE,
          entityName: body.id,
          entityId: body.id,
          newValue: toAuditValue({
            entityType: body.entityType,
            action: body.action,
            name: body.id
          }),
          ...requestMetadata
        });

        return NextResponse.json({
          success: true,
          message: 'อนุมัติชื่อบริษัทเรียบร้อยแล้ว'
        });
      }

      if (scopedUserIds.length > 0) {
        await db
          .update(users)
          .set({
            companyName: organization.name,
            updatedAt: new Date()
          })
          .where(and(inArray(users.id, scopedUserIds), eq(users.companyName, body.id)));
      }

      await updateOrganizationPendingCompanyFlag(organization.id, organization.name);

      await createMasterReviewNotification({
        organizationId: organization.id,
        userId: session.user.id,
        masterType: 'บริษัท',
        entityName: body.id,
        action: 'reject',
        referenceId: body.id
      });

      await logAuditEvent({
        organizationId: organization.id,
        userId: session.user.id,
        module: AUDIT_MODULE.MASTER_REVIEW,
        action: AUDIT_ACTION.REJECT,
        entityName: body.id,
        entityId: body.id,
        newValue: toAuditValue({
          entityType: body.entityType,
          action: body.action,
          name: body.id
        }),
        ...requestMetadata
      });

      return NextResponse.json({
        success: true,
        message: 'ไม่อนุมัติชื่อบริษัทเรียบร้อยแล้ว'
      });
    }

    const targetId = Number(body.id);
    const targetRow =
      body.entityType === 'department'
        ? await db.query.departments.findFirst({
            where: and(eq(departments.id, targetId), eq(departments.organizationId, organization.id))
          })
        : await db.query.positions.findFirst({
            where: and(eq(positions.id, targetId), eq(positions.organizationId, organization.id))
          });

    if (!targetRow) {
      return NextResponse.json({ message: 'ไม่พบข้อมูลหลักที่ต้องการตรวจสอบ' }, { status: 404 });
    }

    if (body.entityType === 'department') {
      if (body.action === 'approve') {
        await db
          .update(departments)
          .set({
            isActive: true,
            pendingMasterReview: false,
            updatedAt: new Date()
          })
          .where(and(eq(departments.id, targetId), eq(departments.organizationId, organization.id)));
      } else {
        if (scopedUserIds.length > 0) {
          await db
            .update(users)
            .set({
              departmentId: null,
              updatedAt: new Date()
            })
            .where(and(inArray(users.id, scopedUserIds), eq(users.departmentId, targetId)));
        }

        await db
          .update(departments)
          .set({
            isActive: false,
            pendingMasterReview: false,
            updatedAt: new Date()
          })
          .where(and(eq(departments.id, targetId), eq(departments.organizationId, organization.id)));
      }

      await createMasterReviewNotification({
        organizationId: organization.id,
        userId: session.user.id,
        masterType: 'แผนก',
        entityName: targetRow.name,
        action: body.action,
        referenceId: targetId
      });

      await logAuditEvent({
        organizationId: organization.id,
        userId: session.user.id,
        module: AUDIT_MODULE.MASTER_REVIEW,
        action: body.action === 'approve' ? AUDIT_ACTION.APPROVE : AUDIT_ACTION.REJECT,
        entityName: targetRow.name,
        entityId: targetId,
        newValue: toAuditValue({
          entityType: body.entityType,
          action: body.action,
          name: targetRow.name
        }),
        ...requestMetadata
      });

      return NextResponse.json({
        success: true,
        message: body.action === 'approve' ? 'อนุมัติแผนกเรียบร้อยแล้ว' : 'ไม่อนุมัติแผนกเรียบร้อยแล้ว'
      });
    }

    if (body.action === 'approve') {
      await db
        .update(positions)
        .set({
          isActive: true,
          pendingMasterReview: false,
          updatedAt: new Date()
        })
        .where(and(eq(positions.id, targetId), eq(positions.organizationId, organization.id)));
    } else {
      if (scopedUserIds.length > 0) {
        await db
          .update(users)
          .set({
            positionId: null,
            updatedAt: new Date()
          })
          .where(and(inArray(users.id, scopedUserIds), eq(users.positionId, targetId)));
      }

      await db
        .update(positions)
        .set({
          isActive: false,
          pendingMasterReview: false,
          updatedAt: new Date()
        })
        .where(and(eq(positions.id, targetId), eq(positions.organizationId, organization.id)));
    }

    await createMasterReviewNotification({
      organizationId: organization.id,
      userId: session.user.id,
      masterType: 'ตำแหน่ง',
      entityName: targetRow.name,
      action: body.action,
      referenceId: targetId
    });

    await logAuditEvent({
      organizationId: organization.id,
      userId: session.user.id,
      module: AUDIT_MODULE.MASTER_REVIEW,
      action: body.action === 'approve' ? AUDIT_ACTION.APPROVE : AUDIT_ACTION.REJECT,
      entityName: targetRow.name,
      entityId: targetId,
      newValue: toAuditValue({
        entityType: body.entityType,
        action: body.action,
        name: targetRow.name
      }),
      ...requestMetadata
    });

    return NextResponse.json({
      success: true,
      message: body.action === 'approve' ? 'อนุมัติตำแหน่งเรียบร้อยแล้ว' : 'ไม่อนุมัติตำแหน่งเรียบร้อยแล้ว'
    });
  } catch (error) {
    if (error instanceof AuthError) {
      return NextResponse.json({ message: error.message }, { status: error.status });
    }

    return NextResponse.json({ message: 'ไม่สามารถอัปเดตรายการรอตรวจสอบได้' }, { status: 500 });
  }
}
