import { AlertCircle, AlertTriangle, CheckCircle2 } from "lucide-react";
import { useDrillStack } from "@/components/drill/DrillStackProvider";
import { PeekModal } from "@/components/drill/PeekModal";
import { ValidationRulePeekContent } from "@/components/drill/ValidationRulePeekContent";
import type { ClaimDetail } from "@/types";

type ValidationPanelProps = {
  validation: ClaimDetail["validation"];
};

type IssueList = ClaimDetail["validation"]["errors"];

/**
 * Group issues by their `rule` field, preserving insertion order so the
 * backend's surface order is respected on screen. Returns an array of
 * `[rule, issues]` pairs — Maps aren't a great fit for JSX iteration here.
 */
function groupByRule(issues: IssueList): Array<[string, IssueList]> {
  const groups = new Map<string, IssueList>();
  for (const issue of issues) {
    const bucket = groups.get(issue.rule);
    if (bucket) {
      bucket.push(issue);
    } else {
      groups.set(issue.rule, [issue]);
    }
  }
  return Array.from(groups.entries());
}

/**
 * One rule-group block: header with rule code + count chip, followed by
 * the list of messages underneath.
 *
 * SP21 Phase 5 Task 5.9: the rule code is now drillable — clicking it
 * opens the validation-rule peek on top of the drawer (via the drill
 * stack). The peek renders ValidationRulePeekContent for the rule
 * code, falling back to a "unknown rule" note when the catalog has
 * no entry. Unknown rules still render the peek so operators can
 * correlate the code to whatever they were just looking at.
 */
function IssueGroup({
  rule,
  issues,
  testId,
}: {
  rule: string;
  issues: IssueList;
  testId: string;
}) {
  const Icon = testId === "validation-errors" ? AlertCircle : AlertTriangle;
  const iconColor =
    testId === "validation-errors"
      ? "text-[color:var(--m-error)]"
      : "text-[color:var(--m-warning)]";
  const { openPeek } = useDrillStack();

  return (
    <div className="flex flex-col gap-1.5">
      <div className="flex items-center gap-2">
        <button
          type="button"
          onClick={() => openPeek({ kind: "rule", rule })}
          data-testid={`${testId}-rule-drill`}
          aria-label={`Drill into rule ${rule}`}
          className="mono text-[12px] font-semibold tracking-tight text-foreground cursor-pointer drillable rounded-sm px-0 -mx-0"
        >
          {rule}
        </button>
        <span
          className="inline-flex items-center rounded-full bg-muted-foreground/15 px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground tabular-nums"
          data-testid={`${testId}-count`}
        >
          {issues.length}
        </span>
      </div>
      <ul className="flex flex-col gap-1.5 pl-1">
        {issues.map((issue, idx) => (
          <li
            key={`${rule}-${idx}`}
            className="flex items-start gap-2 text-[13px] leading-snug text-muted-foreground"
            data-testid={`${testId}-message`}
          >
            <Icon
              className={`mt-0.5 h-3.5 w-3.5 shrink-0 ${iconColor}`}
              strokeWidth={1.75}
              aria-hidden
            />
            <span>{issue.message}</span>
          </li>
        ))}
      </ul>
    </div>
  );
}

/**
 * Validation section of the claim detail drawer (SP4).
 *
 * Three states:
 *  - passed && warnings.length === 0  → "All checks passed" pill
 *  - errors and/or warnings present   → grouped sub-sections
 *
 * Issues are grouped by their `rule` field (e.g. R050_diagnosis_present)
 * with a per-group count, so repeated violations of the same rule don't
 * drown out other rules. Errors render before warnings so the user sees
 * blocking issues first.
 */
export function ValidationPanel({ validation }: ValidationPanelProps) {
  const allPassed = validation.passed && validation.warnings.length === 0;
  // SP21 Phase 5 Task 5.9: peek stack for rule drill. The drill
  // provider is mounted at the App root; we only read the top entry
  // here so the peek renders regardless of which section pushed it.
  const { stack, closeTop } = useDrillStack();
  const topPeek = stack[stack.length - 1];

  if (allPassed) {
    return (
      <section
        data-testid="validation-passed"
        className="flex items-center gap-2 px-6 py-3"
      >
        <CheckCircle2
          className="h-4 w-4 text-[hsl(var(--success))]"
          strokeWidth={1.75}
          aria-hidden
        />
        <span className="text-[13px] font-medium text-foreground">
          All checks passed
        </span>
        <span className="ml-auto inline-flex items-center rounded-full bg-[hsl(var(--success)/0.12)] px-2 py-0.5 text-[10px] font-medium uppercase tracking-[0.14em] text-[hsl(var(--success))]">
          Valid
        </span>
      </section>
    );
  }

  const errorGroups = groupByRule(validation.errors);
  const warningGroups = groupByRule(validation.warnings);

  return (
    <section
      className="flex flex-col gap-4 px-6 py-4"
      data-testid="validation-panel"
    >
      <span className="eyebrow text-muted-foreground">
        Validation
      </span>

      {validation.errors.length > 0 ? (
        <div
          data-testid="validation-errors"
          data-rule-group="errors"
          role="alert"
          className="flex flex-col gap-3 border-l-2 border-[color:var(--m-error)] bg-[hsl(var(--destructive)/0.08)] px-3.5 py-3"
        >
          <div className="flex items-center gap-2">
            <AlertCircle
              className="h-3.5 w-3.5 text-destructive"
              strokeWidth={1.75}
              aria-hidden
            />
            <span className="text-[10.5px] font-semibold uppercase tracking-[0.14em] text-destructive">
              Errors ({validation.errors.length})
            </span>
          </div>
          <div className="flex flex-col gap-3">
            {errorGroups.map(([rule, issues]) => (
              <IssueGroup
                key={rule}
                rule={rule}
                issues={issues}
                testId="validation-errors"
              />
            ))}
          </div>
        </div>
      ) : null}

      {validation.warnings.length > 0 ? (
        <div
          data-testid="validation-warnings"
          data-rule-group="warnings"
          className="flex flex-col gap-3 border-l-2 border-[color:var(--m-warning)] bg-[hsl(var(--warning)/0.08)] px-3.5 py-3"
        >
          <div className="flex items-center gap-2">
            <AlertTriangle
              className="h-3.5 w-3.5 text-[hsl(var(--warning))]"
              strokeWidth={1.75}
              aria-hidden
            />
            <span className="text-[10.5px] font-semibold uppercase tracking-[0.14em] text-[hsl(var(--warning))]">
              Warnings ({validation.warnings.length})
            </span>
          </div>
          <div className="flex flex-col gap-3">
            {warningGroups.map(([rule, issues]) => (
              <IssueGroup
                key={rule}
                rule={rule}
                issues={issues}
                testId="validation-warnings"
              />
            ))}
          </div>
        </div>
      ) : null}

      {/* SP21 Phase 5 Task 5.9: validation-rule peek. Mounted at the
          bottom of the panel so the peek (a Radix Dialog portal) sits
          on top of the drawer. Only renders when the top of the
          drill stack is a rule peek — payer peek (from PartiesGrid)
          wins when it's on top because the stack caps at 1 entry. */}
      {topPeek?.kind === "rule" ? (
        <PeekModal
          open
          onClose={closeTop}
          eyebrow="Validation rule"
          title={topPeek.rule}
        >
          <ValidationRulePeekContent rule={topPeek.rule} />
        </PeekModal>
      ) : null}
    </section>
  );
}
