import { ExperienceFindingPriority, ExperienceFindingStatus } from "@prisma/client";
import { NextResponse } from "next/server";
import { getServerSession } from "next-auth";
import { authOptions } from "@/lib/auth";
import { prisma } from "@/lib/prisma";
import {
  canAccessExperienciometro,
  canManageExperienciometro,
  ensureExperienceBaseline,
  mapExperienceFinding,
  recalculateLocationMetrics,
} from "@/lib/experienciometro";
import type { ExperienceFindingCreatePayload } from "@/lib/experienciometro/types";

function parseDate(value: string | undefined): Date | null {
  if (!value) {
    return null;
  }

  const parsed = new Date(value);
  if (Number.isNaN(parsed.getTime())) {
    return null;
  }

  return parsed;
}

function toPriority(value: string | undefined): ExperienceFindingPriority {
  if (value === "low" || value === "medium" || value === "high" || value === "critical") {
    return value;
  }

  return ExperienceFindingPriority.medium;
}

function toStatus(value: string | undefined): ExperienceFindingStatus {
  if (value === "open" || value === "in_progress" || value === "resolved" || value === "closed") {
    return value;
  }

  return ExperienceFindingStatus.open;
}

export async function GET(request: Request) {
  const session = await getServerSession(authOptions);
  if (!session?.user) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  if (!canAccessExperienciometro(session.user.role)) {
    return NextResponse.json({ error: "Forbidden" }, { status: 403 });
  }

  await ensureExperienceBaseline(prisma, session.user.id);

  const url = new URL(request.url);
  const locationId = url.searchParams.get("locationId")?.trim() || undefined;
  const status = url.searchParams.get("status")?.trim() || undefined;
  const priority = url.searchParams.get("priority")?.trim() || undefined;
  const q = url.searchParams.get("q")?.trim() || undefined;

  const findings = await prisma.experienceFinding.findMany({
    where: {
      ...(locationId ? { locationId } : {}),
      ...(status && status !== "all" ? { status: toStatus(status) } : {}),
      ...(priority && priority !== "all" ? { priority: toPriority(priority) } : {}),
      ...(q
        ? {
            OR: [
              {
                title: {
                  contains: q,
                  mode: "insensitive",
                },
              },
              {
                description: {
                  contains: q,
                  mode: "insensitive",
                },
              },
              {
                categoryLabel: {
                  contains: q,
                  mode: "insensitive",
                },
              },
            ],
          }
        : {}),
    },
    include: {
      responsibleUser: {
        select: {
          name: true,
          email: true,
        },
      },
      createdBy: {
        select: {
          name: true,
          email: true,
        },
      },
    },
    orderBy: [{ createdAt: "desc" }],
    take: 300,
  });

  return NextResponse.json({
    ok: true,
    findings: findings.map(mapExperienceFinding),
  });
}

export async function POST(request: Request) {
  const session = await getServerSession(authOptions);
  if (!session?.user) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  if (!canManageExperienciometro(session.user.role)) {
    return NextResponse.json({ error: "Forbidden" }, { status: 403 });
  }

  await ensureExperienceBaseline(prisma, session.user.id);

  const body = (await request.json()) as ExperienceFindingCreatePayload;
  const locationId = body.locationId?.trim();
  const title = body.title?.trim();

  if (!locationId || !title) {
    return NextResponse.json({ error: "locationId and title are required." }, { status: 400 });
  }

  const location = await prisma.location.findFirst({
    where: {
      id: locationId,
      isActive: true,
    },
    select: { id: true },
  });

  if (!location) {
    return NextResponse.json({ error: "Location not found." }, { status: 404 });
  }

  const dueDate = parseDate(body.dueDate);
  if (body.dueDate && !dueDate) {
    return NextResponse.json({ error: "Invalid dueDate." }, { status: 400 });
  }

  const responsibleUserId = body.responsibleUserId?.trim() || null;
  if (responsibleUserId) {
    const user = await prisma.user.findUnique({
      where: { id: responsibleUserId },
      select: { id: true },
    });

    if (!user) {
      return NextResponse.json({ error: "responsibleUserId is invalid." }, { status: 400 });
    }
  }

  const finding = await prisma.$transaction(async (tx) => {
    const created = await tx.experienceFinding.create({
      data: {
        locationId,
        evaluationId: body.evaluationId?.trim() || null,
        createdById: session.user.id,
        responsibleUserId,
        title,
        description: body.description?.trim() || "",
        categoryKey: body.categoryKey?.trim() || null,
        categoryLabel: body.categoryLabel?.trim() || null,
        priority: toPriority(body.priority),
        status: toStatus(body.status),
        dueDate,
      },
      include: {
        responsibleUser: {
          select: {
            name: true,
            email: true,
          },
        },
        createdBy: {
          select: {
            name: true,
            email: true,
          },
        },
      },
    });

    await recalculateLocationMetrics(tx, locationId);
    return created;
  });

  return NextResponse.json({
    ok: true,
    finding: mapExperienceFinding(finding),
  });
}
