import { FastifyInstance, FastifyRequest, FastifyReply } from "fastify";
import { correlationService } from "@shieldai/correlation";

type AuthUser = { id?: string };

function getUserId(request: FastifyRequest): string | undefined {
  return (request.user as AuthUser | undefined)?.id;
}

export function correlationRoutes(fastify: FastifyInstance) {
  fastify.get("/dashboard", async (request, reply) => {
    const userId = getUserId(request);
    if (!userId || userId === "anonymous") {
      return reply.code(401).send({ error: "User not authenticated" });
    }

    const timeWindow =
      parseInt(
        (request.query as Record<string, string>).timeWindow as string
      ) || 60;
    const data = await correlationService.getDashboardData(userId, timeWindow);
    return reply.send(data);
  });

  fastify.get("/groups", async (request, reply) => {
    const userId = getUserId(request);
    if (!userId || userId === "anonymous") {
      return reply.code(401).send({ error: "User not authenticated" });
    }

    const query = request.query as Record<string, string>;
    const result = await correlationService.getCorrelationGroups({
      userId,
      status: (query.status as any) || undefined,
      timeWindowMinutes: query.timeWindow
        ? parseInt(query.timeWindow)
        : 60,
      limit: query.limit ? parseInt(query.limit) : 50,
      offset: query.offset ? parseInt(query.offset) : 0,
    });
    return reply.send(result);
  });

  fastify.get(
    "/groups/:groupId",
    {
      schema: {
        params: {
          type: "object",
          properties: {
            groupId: { type: "string", format: "uuid" },
          },
          required: ["groupId"],
        },
      },
    },
    async (request, reply) => {
      const userId = getUserId(request);
      if (!userId || userId === "anonymous") {
        return reply.code(401).send({ error: "User not authenticated" });
      }

      const groupId = (request.params as Record<string, string>).groupId;
      const group = await correlationService.getGroupById(groupId, userId);

      if (!group) {
        return reply.code(404).send({ error: "Correlation group not found" });
      }

      return reply.send(group);
    }
  );

  fastify.patch(
    "/groups/:groupId/resolve",
    {
      schema: {
        params: {
          type: "object",
          properties: {
            groupId: { type: "string", format: "uuid" },
          },
          required: ["groupId"],
        },
        body: {
          type: "object",
          properties: {
            status: { type: "string", enum: ["RESOLVED", "ACTIVE"] },
          },
          additionalProperties: false,
        },
      },
    },
    async (request, reply) => {
      const userId = getUserId(request);
      if (!userId || userId === "anonymous") {
        return reply.code(401).send({ error: "User not authenticated" });
      }

      const groupId = (request.params as Record<string, string>).groupId;
      const body = request.body as Record<string, string> | undefined;
      const status = body?.status || "RESOLVED";
      const group = await correlationService.resolveGroup(
        groupId,
        userId,
        status
      );

      if (!group) {
        return reply.code(404).send({ error: "Correlation group not found" });
      }

      return reply.send(group);
    }
  );

  fastify.get("/alerts", async (request, reply) => {
    const userId = getUserId(request);
    if (!userId || userId === "anonymous") {
      return reply.code(401).send({ error: "User not authenticated" });
    }

    const query = request.query as Record<string, string>;
    const result = await correlationService.getCorrelatedAlerts({
      userId,
      source: (query.source as any) || undefined,
      category: (query.category as any) || undefined,
      severity: (query.severity as any) || undefined,
      timeWindowMinutes: query.timeWindow
        ? parseInt(query.timeWindow)
        : 60,
      limit: query.limit ? parseInt(query.limit) : 50,
      offset: query.offset ? parseInt(query.offset) : 0,
    });
    return reply.send(result);
  });

  fastify.post(
    "/ingest/darkwatch",
    {
      schema: {
        body: {
          type: "object",
          properties: {
            sourceAlertId: { type: "string" },
            exposureId: { type: "string" },
            breachName: { type: "string", maxLength: 500 },
            severity: { type: "string", maxLength: 20 },
            channel: { type: "string", maxLength: 50 },
            dataType: { type: "array", items: { type: "string" } },
            dataSource: { type: "string", maxLength: 100 },
          },
          required: ["sourceAlertId", "breachName", "severity", "channel"],
          additionalProperties: false,
        },
      },
    },
    async (request, reply) => {
      const userId = getUserId(request);
      if (!userId || userId === "anonymous") {
        return reply.code(401).send({ error: "User not authenticated" });
      }

      const body = request.body as Record<string, unknown>;
      const alert = await correlationService.ingestDarkWatchAlert(
        userId,
        body.sourceAlertId as string,
        {
          exposureId: body.exposureId as string,
          breachName: body.breachName as string,
          severity: body.severity as string,
          channel: body.channel as string,
          dataType: body.dataType as string[] | undefined,
          dataSource: body.dataSource as string | undefined,
        }
      );
      return reply.code(201).send(alert);
    }
  );

  fastify.post(
    "/ingest/spamshield",
    {
      schema: {
        body: {
          type: "object",
          properties: {
            sourceAlertId: { type: "string" },
            phoneNumber: { type: "string", maxLength: 20 },
            decision: { type: "string", enum: ["BLOCK", "FLAG", "ALLOW"] },
            confidence: { type: "number", minimum: 0, maximum: 1 },
            reasons: { type: "array", items: { type: "string" } },
            channel: { type: "string", enum: ["call", "sms"] },
            hiyaReputationScore: { type: "number" },
            truecallerSpamScore: { type: "number" },
          },
          required: ["sourceAlertId", "phoneNumber", "decision", "confidence"],
          additionalProperties: false,
        },
      },
    },
    async (request, reply) => {
      const userId = getUserId(request);
      if (!userId || userId === "anonymous") {
        return reply.code(401).send({ error: "User not authenticated" });
      }

      const body = request.body as Record<string, unknown>;
      const alert = await correlationService.ingestSpamShieldAlert(
        userId,
        body.sourceAlertId as string,
        {
          phoneNumber: body.phoneNumber as string,
          decision: body.decision as string,
          confidence: body.confidence as number,
          reasons: body.reasons as string[] | undefined,
          channel: body.channel as "call" | "sms" | undefined,
          hiyaReputationScore: body.hiyaReputationScore as
            | number
            | undefined,
          truecallerSpamScore: body.truecallerSpamScore as
            | number
            | undefined,
        }
      );
      return reply.code(201).send(alert);
    }
  );

  fastify.post(
    "/ingest/voiceprint",
    {
      schema: {
        body: {
          type: "object",
          properties: {
            sourceAlertId: { type: "string" },
            jobId: { type: "string" },
            verdict: {
              type: "string",
              enum: ["SYNTHETIC", "NATURAL", "UNCERTAIN"],
            },
            syntheticScore: { type: "number", minimum: 0, maximum: 1 },
            confidence: { type: "number", minimum: 0, maximum: 1 },
            matchedEnrollmentId: { type: "string" },
            matchedSimilarity: { type: "number" },
            analysisType: { type: "string", maxLength: 50 },
          },
          required: [
            "sourceAlertId",
            "jobId",
            "verdict",
            "syntheticScore",
            "confidence",
          ],
          additionalProperties: false,
        },
      },
    },
    async (request, reply) => {
      const userId = getUserId(request);
      if (!userId || userId === "anonymous") {
        return reply.code(401).send({ error: "User not authenticated" });
      }

      const body = request.body as Record<string, unknown>;
      const alert = await correlationService.ingestVoicePrintAlert(
        userId,
        body.sourceAlertId as string,
        {
          jobId: body.jobId as string,
          verdict: body.verdict as string,
          syntheticScore: body.syntheticScore as number,
          confidence: body.confidence as number,
          matchedEnrollmentId: body.matchedEnrollmentId as
            | string
            | undefined,
          matchedSimilarity: body.matchedSimilarity as number | undefined,
          analysisType: body.analysisType as string | undefined,
        }
      );
      return reply.code(201).send(alert);
    }
  );

  fastify.post(
    "/ingest/call-analysis",
    {
      schema: {
        body: {
          type: "object",
          properties: {
            sourceAlertId: { type: "string" },
            callId: { type: "string" },
            eventType: { type: "string", maxLength: 100 },
            mosScore: { type: "number", minimum: 1, maximum: 5 },
            anomaly: { type: "string", maxLength: 500 },
            sentiment: {
              type: "object",
              properties: {
                label: { type: "string", maxLength: 50 },
                score: { type: "number", minimum: 0, maximum: 1 },
              },
            },
          },
          required: ["sourceAlertId", "callId"],
          additionalProperties: false,
        },
      },
    },
    async (request, reply) => {
      const userId = getUserId(request);
      if (!userId || userId === "anonymous") {
        return reply.code(401).send({ error: "User not authenticated" });
      }

      const body = request.body as Record<string, unknown>;
      const alert = await correlationService.ingestCallAnalysisAlert(
        userId,
        body.sourceAlertId as string,
        {
          callId: body.callId as string,
          eventType: body.eventType as string | undefined,
          mosScore: body.mosScore as number | undefined,
          anomaly: body.anomaly as string | undefined,
          sentiment: body.sentiment as
            | { label: string; score: number }
            | undefined,
        }
      );
      return reply.code(201).send(alert);
    }
  );
}
