import { Injectable } from "@nestjs/common";
import { PrismaService } from "../prisma/prisma.service";
import type { ParsedPolicy } from "./parsers/policy-parser";

export interface MatchResult {
  policyId: string | null;
  customerId: string | null;
  /** Why it landed here — shown in the review queue verbatim. */
  note: string;
  /** True only for an unambiguous hit on `Policy.policyNumber`. */
  confident: boolean;
  /**
   * Every policy that carries the parsed number, with its customer. >1 means
   * the policy number is shared across customers and a human must pick.
   */
  candidates: { policyId: string; customerId: string; customerName: string; policyNumber: string }[];
}

/**
 * Resolves a parsed policy page to an existing Policy (and its customer) the
 * office already holds.
 *
 * **Match on `Policy.policyNumber` alone, never on the printed insured name.**
 * The certificate's "Insured" line is the account's registrant, which drifts
 * from the current owner — the same problem the statement matcher cites for
 * utility bills ("ARNAIZ ROSAS ELSA AURORA" on a CESPT receipt for a
 * customer this office holds as "CATT, RANDY"). Names are surfaced for the
 * reviewer to sanity-check and never feed matching.
 *
 * A policy number that matches zero rows means the policy is new: the
 * review screen then offers a customer picker and the confirm step creates
 * the row. Multiple hits are surfaced rather than auto-picked — duplicate
 * policy numbers across customers do occur (same group policy bound by two
 * related parties), and picking one arbitrarily would silently book the
 * wrong coverage.
 */
@Injectable()
export class PolicyMatcherService {
  constructor(private readonly prisma: PrismaService) {}

  async match(parsed: ParsedPolicy): Promise<MatchResult> {
    if (!parsed.policyNumber) {
      return this.unmatched("no se pudo leer el número de póliza");
    }

    const rows = await this.prisma.policy.findMany({
      where: { policyNumber: parsed.policyNumber },
      select: {
        id: true,
        policyNumber: true,
        customerId: true,
        customer: { select: { name: true } },
      },
    });

    const candidates = rows.map((r) => ({
      policyId: r.id,
      customerId: r.customerId,
      customerName: r.customer.name,
      policyNumber: r.policyNumber,
    }));

    if (rows.length === 0) {
      return {
        policyId: null,
        customerId: null,
        note: `no se encontró ninguna póliza con el número ${parsed.policyNumber}`,
        confident: false,
        candidates: [],
      };
    }

    if (rows.length > 1) {
      return {
        policyId: null,
        customerId: null,
        note: `${rows.length} pólizas comparten el número ${parsed.policyNumber}`,
        confident: false,
        candidates,
      };
    }

    return {
      policyId: candidates[0].policyId,
      customerId: candidates[0].customerId,
      note: `coincidencia exacta por número de póliza ${parsed.policyNumber}`,
      confident: true,
      candidates,
    };
  }

  private unmatched(note: string): MatchResult {
    return {
      policyId: null,
      customerId: null,
      note,
      confident: false,
      candidates: [],
    };
  }
}