"use client";

import { PkmWriteCoordinator } from "@/lib/services/pkm-write-coordinator";
import type { PkmWriteCoordinatorResult } from "@/lib/services/pkm-write-coordinator";

export const KYC_WORKFLOW_PKM_DOMAIN = "kyc_workflow" as const;

export type KycWorkflowStatus = "verified" | "pending" | "failed" | "not_started";
export type KycWorkflowCheckKey = "identity" | "address" | "bank" | "email";

export type KycWorkflowCheck = {
  status: KycWorkflowStatus;
  updated_at: string | null;
  method: string | null;
  source_domain: string | null;
};

export type KycWorkflowSentReplySnapshot = {
  workflow_id: string;
  subject: string | null;
  body: string;
  html_body: string | null;
  to: string[];
  cc: string[];
  sent_at: string;
  draft_hash: string | null;
  schema_version: 1;
};

export type KycWorkflowArtifact = {
  checks: Record<KycWorkflowCheckKey, KycWorkflowCheck>;
  overall_status: KycWorkflowStatus;
  counterparty: string | null;
  request_summary: string | null;
  pending_requirements: string[];
  completed_requirements: string[];
  sent_replies?: Record<string, KycWorkflowSentReplySnapshot>;
  last_updated: string;
  schema_version: 1;
};

export type KycWorkflowArtifactInput = Omit<KycWorkflowArtifact, "last_updated" | "schema_version">;

export type KycWorkflowPkmWriteParams = {
  userId: string;
  vaultKey: string | null;
  vaultOwnerToken: string | null;
  artifact: KycWorkflowArtifact;
};

export type KycWorkflowPkmReadResult = {
  found: boolean;
  artifact: KycWorkflowArtifact | null;
};

function emptyCheck(): KycWorkflowCheck {
  return {
    status: "not_started",
    updated_at: null,
    method: null,
    source_domain: null,
  };
}

function normalizeCheck(value: unknown): KycWorkflowCheck {
  if (!value || typeof value !== "object") return emptyCheck();
  const record = value as Partial<KycWorkflowCheck>;
  return {
    status: record.status ?? "not_started",
    updated_at: record.updated_at ?? null,
    method: record.method ?? null,
    source_domain: record.source_domain ?? null,
  };
}

function normalizeChecks(value: unknown): KycWorkflowArtifact["checks"] {
  const record = value && typeof value === "object"
    ? value as Partial<Record<KycWorkflowCheckKey, unknown>>
    : {};
  return {
    identity: normalizeCheck(record.identity),
    address: normalizeCheck(record.address),
    bank: normalizeCheck(record.bank),
    email: normalizeCheck(record.email),
  };
}

function buildKycSummary(artifact: KycWorkflowArtifact): Record<string, unknown> {
  return {
    workflow_type: "kyc",
    overall_status: artifact.overall_status,
    identity_verified: artifact.checks.identity.status === "verified",
    address_verified: artifact.checks.address.status === "verified",
    bank_linked: artifact.checks.bank.status === "verified",
    email_verified: artifact.checks.email.status === "verified",
    pending_requirement_count: artifact.pending_requirements.length,
    completed_requirement_count: artifact.completed_requirements.length,
    sent_reply_count: Object.keys(artifact.sent_replies || {}).length,
    last_updated: artifact.last_updated,
  };
}

export function buildKycWorkflowArtifact(
  artifact: KycWorkflowArtifactInput,
  lastUpdated = new Date().toISOString()
): KycWorkflowArtifact {
  return {
    ...artifact,
    last_updated: lastUpdated,
    schema_version: 1,
  };
}

export async function hashKycWorkflowArtifact(artifact: KycWorkflowArtifact): Promise<string> {
  const digest = await crypto.subtle.digest(
    "SHA-256",
    new TextEncoder().encode(JSON.stringify(artifact))
  );
  return Array.from(new Uint8Array(digest))
    .map((byte) => byte.toString(16).padStart(2, "0"))
    .join("");
}

function mergeCheck(
  next: KycWorkflowCheck,
  existing: KycWorkflowCheck | undefined
): KycWorkflowCheck {
  if (next.status !== "not_started") return next;
  return existing ?? next;
}

export function mergeKycWorkflowArtifact(
  artifact: KycWorkflowArtifact,
  existing: KycWorkflowArtifact | null
): KycWorkflowArtifact {
  const sentReplies = {
    ...(existing?.sent_replies || {}),
    ...(artifact.sent_replies || {}),
  };
  return {
    checks: {
      identity: mergeCheck(artifact.checks.identity, existing?.checks.identity),
      address: mergeCheck(artifact.checks.address, existing?.checks.address),
      bank: mergeCheck(artifact.checks.bank, existing?.checks.bank),
      email: mergeCheck(artifact.checks.email, existing?.checks.email),
    },
    overall_status: artifact.overall_status,
    counterparty: artifact.counterparty ?? existing?.counterparty ?? null,
    request_summary: artifact.request_summary ?? existing?.request_summary ?? null,
    pending_requirements: artifact.pending_requirements,
    completed_requirements: artifact.completed_requirements,
    sent_replies: Object.keys(sentReplies).length ? sentReplies : undefined,
    last_updated: artifact.last_updated,
    schema_version: 1,
  };
}

export class KycWorkflowPkmService {
  static async writeWorkflowArtifact(
    params: KycWorkflowPkmWriteParams
  ): Promise<PkmWriteCoordinatorResult> {
    const artifact = params.artifact;

    return PkmWriteCoordinator.saveMergedDomain({
      userId: params.userId,
      domain: KYC_WORKFLOW_PKM_DOMAIN,
      vaultKey: params.vaultKey,
      vaultOwnerToken: params.vaultOwnerToken,
      build: (context) => {
        const existing = this.readWorkflowArtifact(context.currentDomainData).artifact;
        const merged = mergeKycWorkflowArtifact(artifact, existing);
        return {
          domainData: merged as unknown as Record<string, unknown>,
          summary: buildKycSummary(merged),
        };
      },
    });
  }

  static readWorkflowArtifact(
    domainData: Record<string, unknown> | null
  ): KycWorkflowPkmReadResult {
    if (!domainData) {
      return { found: false, artifact: null };
    }

    const checks = normalizeChecks(domainData.checks);
    const hasChecks = Object.values(checks).some((check) => check.status !== "not_started");
    const pendingRequirements = Array.isArray(domainData.pending_requirements)
      ? domainData.pending_requirements.filter((item): item is string => typeof item === "string")
      : [];
    const completedRequirements = Array.isArray(domainData.completed_requirements)
      ? domainData.completed_requirements.filter((item): item is string => typeof item === "string")
      : [];
    const sentReplies = normalizeSentReplies(domainData.sent_replies);

    if (
      !hasChecks &&
      pendingRequirements.length === 0 &&
      completedRequirements.length === 0 &&
      Object.keys(sentReplies).length === 0
    ) {
      return { found: false, artifact: null };
    }

    const artifact: KycWorkflowArtifact = {
      checks,
      overall_status: (domainData.overall_status as KycWorkflowStatus) ?? "not_started",
      counterparty: typeof domainData.counterparty === "string" ? domainData.counterparty : null,
      request_summary: typeof domainData.request_summary === "string"
        ? domainData.request_summary
        : null,
      pending_requirements: pendingRequirements,
      completed_requirements: completedRequirements,
      sent_replies: Object.keys(sentReplies).length ? sentReplies : undefined,
      last_updated: (domainData.last_updated as string) ?? new Date().toISOString(),
      schema_version: 1,
    };

    return { found: true, artifact };
  }
}

function normalizeStringArray(value: unknown): string[] {
  return Array.isArray(value)
    ? value.map((item) => String(item || "").trim()).filter(Boolean)
    : [];
}

function normalizeSentReplies(value: unknown): Record<string, KycWorkflowSentReplySnapshot> {
  if (!value || typeof value !== "object" || Array.isArray(value)) return {};
  const snapshots: Record<string, KycWorkflowSentReplySnapshot> = {};
  for (const [workflowId, raw] of Object.entries(value as Record<string, unknown>)) {
    if (!raw || typeof raw !== "object" || Array.isArray(raw)) continue;
    const record = raw as Record<string, unknown>;
    const body = typeof record.body === "string" ? record.body : "";
    if (!body.trim()) continue;
    const id = typeof record.workflow_id === "string" && record.workflow_id.trim()
      ? record.workflow_id.trim()
      : workflowId;
    snapshots[id] = {
      workflow_id: id,
      subject: typeof record.subject === "string" ? record.subject : null,
      body,
      html_body: typeof record.html_body === "string" ? record.html_body : null,
      to: normalizeStringArray(record.to),
      cc: normalizeStringArray(record.cc),
      sent_at: typeof record.sent_at === "string" ? record.sent_at : new Date().toISOString(),
      draft_hash: typeof record.draft_hash === "string" ? record.draft_hash : null,
      schema_version: 1,
    };
  }
  return snapshots;
}
