import { NextResponse } from 'next/server';
import { and, eq, isNull, gte, sql } from 'drizzle-orm';

import { withAuth, withPermission } from '@/lib/api/helpers';
import { db } from '@/lib/db';
import { interests } from '@/lib/db/schema/interests';
import { berths } from '@/lib/db/schema/berths';
import { clients } from '@/lib/db/schema/clients';
import { websiteSubmissions } from '@/lib/db/schema/website-submissions';
import { errorResponse } from '@/lib/errors';
import { PIPELINE_STAGES } from '@/lib/constants';

export const GET = withAuth(
  withPermission('reports', 'view_dashboard', async (_req, ctx) => {
    try {
      const portId = ctx.portId;
      const sevenDaysAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000);
      const thirtyDaysAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);

      const [pipelineRows, berthStatusRows, totals, recent] = await Promise.all([
        db
          .select({
            stage: interests.pipelineStage,
            count: sql<number>`count(*)::int`,
          })
          .from(interests)
          .where(and(eq(interests.portId, portId), isNull(interests.archivedAt)))
          .groupBy(interests.pipelineStage),

        db
          .select({
            status: berths.status,
            count: sql<number>`count(*)::int`,
          })
          .from(berths)
          .where(eq(berths.portId, portId))
          .groupBy(berths.status),

        Promise.all([
          db
            .select({ count: sql<number>`count(*)::int` })
            .from(clients)
            .where(and(eq(clients.portId, portId), isNull(clients.archivedAt))),
          db
            .select({ count: sql<number>`count(*)::int` })
            .from(interests)
            .where(and(eq(interests.portId, portId), isNull(interests.archivedAt))),
          db
            .select({ count: sql<number>`count(*)::int` })
            .from(berths)
            .where(eq(berths.portId, portId)),
        ]),

        Promise.all([
          db
            .select({ count: sql<number>`count(*)::int` })
            .from(websiteSubmissions)
            .where(
              and(
                eq(websiteSubmissions.portId, portId),
                gte(websiteSubmissions.receivedAt, sevenDaysAgo),
              ),
            ),
          db
            .select({ count: sql<number>`count(*)::int` })
            .from(interests)
            .where(
              and(
                eq(interests.portId, portId),
                eq(interests.pipelineStage, 'completed'),
                gte(interests.updatedAt, thirtyDaysAgo),
              ),
            ),
        ]),
      ]);

      const pipeline = Object.fromEntries(PIPELINE_STAGES.map((s) => [s, 0])) as Record<
        string,
        number
      >;
      for (const row of pipelineRows) pipeline[row.stage] = row.count;

      const berthStatus: Record<string, number> = {
        available: 0,
        under_offer: 0,
        sold: 0,
      };
      for (const row of berthStatusRows) berthStatus[row.status] = row.count;

      const totalClients = totals[0][0]?.count ?? 0;
      const totalInterests = totals[1][0]?.count ?? 0;
      const totalBerths = totals[2][0]?.count ?? 0;
      const newInquiries7d = recent[0][0]?.count ?? 0;
      const completed30d = recent[1][0]?.count ?? 0;

      const closedTotal = pipeline['completed'] ?? 0;
      const openTotal = totalInterests - closedTotal;
      const conversionPct =
        totalInterests > 0 ? Math.round((closedTotal / totalInterests) * 100) : 0;

      return NextResponse.json({
        data: {
          totals: { totalClients, totalInterests, totalBerths },
          recent: { newInquiries7d, completed30d },
          pipeline,
          berthStatus,
          conversion: { closedTotal, openTotal, conversionPct },
        },
      });
    } catch (error) {
      return errorResponse(error);
    }
  }),
);
