import { DomainError } from "../../shared/errors.ts";

export type KycStatus = "draft" | "pending" | "approved" | "rejected";

export interface KycEvidenceInput {
  readonly idFrontObjectKey?: string;
  readonly idBackObjectKey?: string;
  readonly selfieObjectKey?: string;
  readonly challengeDate: string;
}

export interface KycSubmission {
  readonly id: string;
  readonly sellerId: string;
  readonly sequence: number;
  readonly status: KycStatus;
  readonly challengeDate: string;
  readonly submittedAt?: Date;
  readonly reviewedAt?: Date;
  readonly reviewedBy?: string;
  readonly rejectionReason?: string;
}

function dateInTimezone(now: Date, timezone: string): string {
  const parts = new Intl.DateTimeFormat("en-CA", {
    timeZone: timezone, year: "numeric", month: "2-digit", day: "2-digit",
  }).formatToParts(now);
  const value = (type: string) => parts.find((part) => part.type === type)?.value;
  return `${value("year")}-${value("month")}-${value("day")}`;
}

export function requiredChallengeDate(now: Date, timezone: string): string {
  try { return dateInTimezone(now, timezone); }
  catch { throw new DomainError("INVALID_TIMEZONE", "Configured application timezone is invalid."); }
}

export function submitKyc(
  draft: KycSubmission,
  evidence: KycEvidenceInput,
  now: Date,
  timezone: string,
): KycSubmission {
  if (draft.status !== "draft") throw new DomainError("KYC_NOT_DRAFT", "Only a new draft can be submitted.");
  if (!evidence.idFrontObjectKey || !evidence.idBackObjectKey || !evidence.selfieObjectKey) {
    throw new DomainError("KYC_EVIDENCE_REQUIRED", "ID front, ID back and challenge selfie are required.");
  }
  const required = requiredChallengeDate(now, timezone);
  if (evidence.challengeDate !== required) throw new DomainError("STALE_KYC_CHALLENGE", "The selfie challenge date is not current.");
  return { ...draft, status: "pending", challengeDate: required, submittedAt: now };
}

export function reviewKyc(
  pending: KycSubmission,
  decision: "approved" | "rejected",
  reviewerId: string,
  now: Date,
  rejectionReason?: string,
): KycSubmission {
  if (pending.status !== "pending") throw new DomainError("KYC_NOT_PENDING", "Only a pending submission can be reviewed.");
  if (decision === "rejected" && !rejectionReason?.trim()) throw new DomainError("REJECTION_REASON_REQUIRED", "A safe rejection reason is required.");
  return {
    ...pending,
    status: decision,
    reviewedBy: reviewerId,
    reviewedAt: now,
    ...(decision === "rejected" ? { rejectionReason: rejectionReason!.trim() } : {}),
  };
}

export function createResubmission(previous: KycSubmission, newId: string): KycSubmission {
  if (previous.status !== "rejected") throw new DomainError("KYC_NOT_REJECTED", "Only rejected verification can be resubmitted.");
  return { id: newId, sellerId: previous.sellerId, sequence: previous.sequence + 1, status: "draft", challengeDate: "" };
}

export function assertSellerMaySell(latest: KycSubmission | null): void {
  if (!latest || latest.status !== "approved") throw new DomainError("SELLER_KYC_REQUIRED", "Approved seller verification is required.");
}
