'use client';

import { useRouter } from 'next/navigation';
import { useState } from 'react';
import { Check, Download, FileWarning, RotateCcw, X } from 'lucide-react';
import {
  Button,
  ConfirmDialog,
  FormError,
  WorkflowStatus,
  cn,
  humanizeStatus,
} from '@i-learned/ui';

interface ApiError {
  error: { code: string; message: string; details?: Array<{ path: string; message: string }> };
}

export interface ReviewableRequirement {
  id: string;
  name: string;
  code: string;
  status: string;
  isMandatory: boolean;
  requiresUpload: boolean;
  currentSubmissionId: string | null;
  version: number | null;
  submittedAt: string | null;
  note: string | null;
  hasFile: boolean;
  lastReason: string | null;
  lastComment: string | null;
}

type Decision = 'ACCEPTED' | 'REJECTED' | 'NEEDS_RESUBMISSION' | 'WAIVED';

/** Decisions that require a reason, mirroring the workflow's own rule. */
const REASON_REQUIRED: Decision[] = ['REJECTED', 'NEEDS_RESUBMISSION', 'WAIVED'];

const DECISION_LABELS: Record<Decision, string> = {
  ACCEPTED: 'Accept',
  REJECTED: 'Reject',
  NEEDS_RESUBMISSION: 'Request resubmission',
  WAIVED: 'Waive',
};

/**
 * The requirement checklist with review controls (SPEC.md §11).
 *
 * Every rejecting decision opens a dialog that will not submit without a
 * reason — the same rule the server enforces, surfaced before the round trip so
 * the reviewer is not told "no" after typing everything else.
 */
export function RequirementReview({
  requirements,
  canReview,
  canDownload,
}: {
  requirements: readonly ReviewableRequirement[];
  canReview: boolean;
  canDownload: boolean;
}): React.JSX.Element {
  const router = useRouter();
  const [error, setError] = useState<ApiError['error'] | null>(null);
  const [busy, setBusy] = useState(false);
  const [downloading, setDownloading] = useState<string | null>(null);

  const [pending, setPending] = useState<{ id: string; decision: Decision; name: string } | null>(
    null,
  );
  const [reason, setReason] = useState('');

  async function submitDecision(): Promise<void> {
    if (!pending) return;
    setBusy(true);
    setError(null);

    const response = await fetch(`/api/v1/requirements/${pending.id}/review`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        decision: pending.decision,
        reason: reason.trim() || undefined,
        comment: pending.decision === 'ACCEPTED' ? 'Verified against the submitted document.' : undefined,
      }),
    });

    setBusy(false);

    if (!response.ok) {
      setError(((await response.json()) as ApiError).error);
      setPending(null);
      return;
    }

    setPending(null);
    setReason('');
    router.refresh();
  }

  /**
   * Opens the stored document.
   *
   * The link is fetched on demand rather than rendered into the page, because
   * it expires in five minutes and issuing it is an audited sensitive read —
   * a page full of pre-issued links would log a read of every document
   * regardless of what the reviewer actually opened.
   */
  async function openDocument(submissionId: string): Promise<void> {
    setDownloading(submissionId);
    setError(null);

    const response = await fetch(`/api/v1/requirements/submissions/${submissionId}/download`);
    setDownloading(null);

    if (!response.ok) {
      setError(((await response.json()) as ApiError).error);
      return;
    }

    const { data } = (await response.json()) as { data: { url: string } };
    window.open(data.url, '_blank', 'noopener,noreferrer');
  }

  return (
    <div className="space-y-3">
      {error ? (
        <FormError title="That review could not be saved" message={error.message} details={error.details} />
      ) : null}

      <ul className="divide-y divide-border">
        {requirements.map((requirement) => (
          <li key={requirement.id} className="py-3 first:pt-0 last:pb-0">
            <div className="flex flex-wrap items-start justify-between gap-3">
              <div className="min-w-0 flex-1">
                <p className="flex flex-wrap items-center gap-2 text-sm font-medium text-ink">
                  {requirement.name}
                  {!requirement.isMandatory ? (
                    <span className="rounded bg-surface-sunken px-1.5 py-0.5 text-[10px] font-medium uppercase text-ink-subtle">
                      Optional
                    </span>
                  ) : null}
                  {!requirement.requiresUpload ? (
                    <span className="rounded bg-info-bg px-1.5 py-0.5 text-[10px] font-medium uppercase text-info">
                      Physical item
                    </span>
                  ) : null}
                </p>

                <p className="mt-1 flex flex-wrap items-center gap-2 text-xs text-ink-subtle">
                  <WorkflowStatus status={requirement.status} size="sm" />
                  {requirement.version !== null ? <span>Version {requirement.version}</span> : null}
                  {requirement.submittedAt ? (
                    <span>Submitted {new Date(requirement.submittedAt).toLocaleDateString()}</span>
                  ) : null}
                </p>

                {requirement.note ? (
                  <p className="mt-1.5 text-sm text-ink-muted">{requirement.note}</p>
                ) : null}

                {requirement.lastReason ? (
                  <p className="mt-1.5 rounded border-l-2 border-warning/50 bg-warning-bg px-2.5 py-1.5 text-sm text-ink-muted">
                    <span className="font-medium">Reason: </span>
                    {requirement.lastReason}
                  </p>
                ) : null}
              </div>

              <div className="flex shrink-0 flex-wrap items-center gap-1.5">
                {requirement.hasFile && requirement.currentSubmissionId && canDownload ? (
                  <Button
                    size="sm"
                    variant="secondary"
                    loading={downloading === requirement.currentSubmissionId}
                    onClick={() => openDocument(requirement.currentSubmissionId as string)}
                  >
                    <Download className="size-4" aria-hidden="true" />
                    Open
                  </Button>
                ) : null}

                {canReview ? (
                  <>
                    {requirement.status !== 'ACCEPTED' ? (
                      <Button
                        size="sm"
                        onClick={() =>
                          setPending({
                            id: requirement.id,
                            decision: 'ACCEPTED',
                            name: requirement.name,
                          })
                        }
                      >
                        <Check className="size-4" aria-hidden="true" />
                        Accept
                      </Button>
                    ) : null}

                    {requirement.status === 'SUBMITTED' ||
                    requirement.status === 'UNDER_REVIEW' ||
                    requirement.status === 'ACCEPTED' ? (
                      <Button
                        size="sm"
                        variant="secondary"
                        onClick={() =>
                          setPending({
                            id: requirement.id,
                            decision: 'NEEDS_RESUBMISSION',
                            name: requirement.name,
                          })
                        }
                      >
                        <RotateCcw className="size-4" aria-hidden="true" />
                        Resubmit
                      </Button>
                    ) : null}

                    {requirement.status === 'SUBMITTED' || requirement.status === 'UNDER_REVIEW' ? (
                      <Button
                        size="sm"
                        variant="ghost"
                        className="text-danger hover:bg-danger-bg"
                        onClick={() =>
                          setPending({
                            id: requirement.id,
                            decision: 'REJECTED',
                            name: requirement.name,
                          })
                        }
                      >
                        <X className="size-4" aria-hidden="true" />
                        Reject
                      </Button>
                    ) : null}

                    {requirement.status === 'NOT_SUBMITTED' ||
                    requirement.status === 'REJECTED' ? (
                      <Button
                        size="sm"
                        variant="ghost"
                        onClick={() =>
                          setPending({
                            id: requirement.id,
                            decision: 'WAIVED',
                            name: requirement.name,
                          })
                        }
                      >
                        <FileWarning className="size-4" aria-hidden="true" />
                        Waive
                      </Button>
                    ) : null}
                  </>
                ) : null}
              </div>
            </div>
          </li>
        ))}
      </ul>

      <ConfirmDialog
        open={pending !== null}
        onOpenChange={(open) => {
          if (!open) {
            setPending(null);
            setReason('');
          }
        }}
        title={pending ? `${DECISION_LABELS[pending.decision]} “${pending.name}”?` : ''}
        description={
          pending?.decision === 'ACCEPTED'
            ? 'The applicant will see this requirement as satisfied.'
            : 'The applicant will see this decision and your reason, so they know exactly what to do next.'
        }
        confirmLabel={pending ? DECISION_LABELS[pending.decision] : 'Confirm'}
        tone={pending?.decision === 'REJECTED' ? 'danger' : 'default'}
        loading={busy}
        reason={
          pending && REASON_REQUIRED.includes(pending.decision)
            ? {
                label: 'Reason',
                value: reason,
                onChange: setReason,
                placeholder:
                  pending.decision === 'WAIVED'
                    ? 'Submitted in person at the Admissions counter.'
                    : 'The uploaded scan is illegible. Please submit a clearer copy.',
              }
            : undefined
        }
        onConfirm={submitDecision}
      />
    </div>
  );
}

/** Compact status summary for a checklist, used above the list. */
export function RequirementSummary({
  satisfied,
  total,
  className,
}: {
  satisfied: number;
  total: number;
  className?: string;
}): React.JSX.Element {
  const complete = total > 0 && satisfied === total;

  return (
    <p className={cn('text-sm', complete ? 'text-success' : 'text-ink-muted', className)}>
      <span className="font-semibold tabular-nums">
        {satisfied}/{total}
      </span>{' '}
      mandatory requirements {complete ? 'satisfied' : 'satisfied'}
      {!complete ? ` — ${total - satisfied} outstanding` : ''}
    </p>
  );
}

export { humanizeStatus };
