import { normalizeEstimateDemandLine, summarizeEstimateDemandLines } from "@capakraken/engine";
import { CreateEstimateSchema } from "@capakraken/shared";
import { z } from "zod";
import { lookupRate } from "../lib/rate-card-lookup.js";

function buildComputedMetrics(
  demandLines: z.infer<typeof CreateEstimateSchema>["demandLines"],
) {
  const summary = summarizeEstimateDemandLines(demandLines);

  return [
    {
      key: "total_hours",
      label: "Total Hours",
      metricGroup: "summary",
      valueDecimal: summary.totalHours,
      metadata: {},
    },
    {
      key: "total_cost",
      label: "Total Cost",
      metricGroup: "summary",
      valueDecimal: summary.totalCostCents / 100,
      valueCents: summary.totalCostCents,
      currency: demandLines[0]?.currency ?? "EUR",
      metadata: {},
    },
    {
      key: "total_price",
      label: "Total Price",
      metricGroup: "summary",
      valueDecimal: summary.totalPriceCents / 100,
      valueCents: summary.totalPriceCents,
      currency: demandLines[0]?.currency ?? "EUR",
      metadata: {},
    },
    {
      key: "margin",
      label: "Margin",
      metricGroup: "summary",
      valueDecimal: summary.marginCents / 100,
      valueCents: summary.marginCents,
      currency: demandLines[0]?.currency ?? "EUR",
      metadata: {},
    },
    {
      key: "margin_percent",
      label: "Margin %",
      metricGroup: "summary",
      valueDecimal: summary.marginPercent,
      metadata: {},
    },
  ];
}

function normalizeDemandLines<
  T extends {
    demandLines: z.infer<typeof CreateEstimateSchema>["demandLines"];
    resourceSnapshots: z.infer<typeof CreateEstimateSchema>["resourceSnapshots"];
  },
>(input: T, baseCurrency: string) {
  const snapshotsByResourceId = new Map(
    input.resourceSnapshots
      .filter(
        (snapshot): snapshot is (typeof input.resourceSnapshots)[number] & {
          resourceId: string;
        } => typeof snapshot.resourceId === "string" && snapshot.resourceId.length > 0,
      )
      .map((snapshot) => [snapshot.resourceId, snapshot]),
  );

  return input.demandLines.map((line) =>
    normalizeEstimateDemandLine(line, {
      resourceSnapshot:
        line.resourceId != null ? snapshotsByResourceId.get(line.resourceId) : null,
      defaultCurrency: baseCurrency,
    }),
  );
}

export function withComputedMetrics<
  T extends {
    demandLines: z.infer<typeof CreateEstimateSchema>["demandLines"];
    resourceSnapshots: z.infer<typeof CreateEstimateSchema>["resourceSnapshots"];
    metrics: z.infer<typeof CreateEstimateSchema>["metrics"];
  },
>(input: T, baseCurrency: string) {
  const normalizedDemandLines = normalizeDemandLines(input, baseCurrency);
  const computedMetrics = buildComputedMetrics(normalizedDemandLines);
  const computedKeys = new Set(computedMetrics.map((metric) => metric.key));

  return {
    ...input,
    demandLines: normalizedDemandLines,
    metrics: [
      ...input.metrics.filter((metric) => !computedKeys.has(metric.key)),
      ...computedMetrics,
    ],
  };
}

export async function autoFillDemandLineRates(
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  db: any,
  demandLines: z.infer<typeof CreateEstimateSchema>["demandLines"],
  projectId?: string | null,
): Promise<{
  demandLines: z.infer<typeof CreateEstimateSchema>["demandLines"];
  autoFilledIndices: number[];
}> {
  let clientId: string | null = null;
  if (projectId) {
    const project = await db.project.findUnique({
      where: { id: projectId },
      select: { clientId: true },
    });
    clientId = project?.clientId ?? null;
  }

  const autoFilledIndices: number[] = [];
  const enriched = await Promise.all(
    demandLines.map(async (line, index) => {
      const isDefaultRate = line.costRateCents === 0 && line.billRateCents === 0;
      const hasExplicitSource = line.rateSource != null && line.rateSource.length > 0;
      if (!isDefaultRate || hasExplicitSource) {
        return line;
      }

      const result = await lookupRate(db, {
        clientId,
        chapter: line.chapter ?? null,
        roleId: line.roleId ?? null,
      });
      if (!result) {
        return line;
      }

      autoFilledIndices.push(index);
      const existingMetadata = (line.metadata ?? {}) as Record<string, unknown>;
      return {
        ...line,
        costRateCents: result.costRateCents,
        billRateCents: result.billRateCents,
        currency: result.currency,
        rateSource: `rate-card:${result.rateCardId}`,
        metadata: {
          ...existingMetadata,
          autoAppliedRateCard: {
            rateCardId: result.rateCardId,
            rateCardLineId: result.rateCardLineId,
            rateCardName: result.rateCardName,
            appliedAt: new Date().toISOString(),
          },
        },
      };
    }),
  );

  return { demandLines: enriched, autoFilledIndices };
}
