/**
 * `<RecoveryRequest />` — new-device widget for V3.10 social key
 * recovery.
 *
 * The user provides the recovery-card values they recorded at setup
 * time (originalAddress, setupId, threshold, guardian list). The
 * widget shows the new device's TEMPORARY identity fingerprint
 * prominently — the user reads it OOB to each guardian to authorize
 * the share release — then runs `requestRecovery` and reports
 * progress as guardians respond.
 *
 * On success the widget surfaces the restored fingerprint so the
 * user can sanity-check it against the value on the recovery card
 * before continuing in the app.
 */

import React, { useEffect, useMemo, useState } from 'react';
import {
  RecoveryDeclinedError,
  RecoveryReconstructionError,
  RecoveryTimeoutError,
  requestRecovery,
  type RecoveryDeliver,
  type RecoveryProgress,
  type RecoveryResult,
} from '@shade/recovery';
import { useShadeRuntime, useShadeRuntimeTheme } from '../../ShadeRuntimeProvider.js';
import { formatOobText } from '../FingerprintGate.js';

export interface RecoveryRequestProps {
  /** Address of the original (lost) identity. From the recovery card. */
  originalAddress: string;
  /** Setup id from the recovery card. */
  setupId: string;
  /** Reconstruction threshold. From the recovery card. */
  threshold: number;
  /** Guardian addresses to query. Caller can preselect or let user choose. */
  guardians: ReadonlyArray<string>;
  /** Outbound transport callback. */
  deliver: RecoveryDeliver;
  /** Override timeout in ms (defaults to 5 min). */
  timeoutMs?: number;
  /** Fired on successful recovery. */
  onComplete?: (result: RecoveryResult) => void;
  /** Fired on terminal failure. */
  onError?: (err: Error) => void;
}

type Phase =
  | { kind: 'idle' }
  | { kind: 'running'; progress: RecoveryProgress | null }
  | { kind: 'done'; result: RecoveryResult }
  | { kind: 'failed'; error: Error };

export function RecoveryRequest(props: RecoveryRequestProps): React.ReactElement {
  const runtime = useShadeRuntime();
  const theme = useShadeRuntimeTheme();
  const [phase, setPhase] = useState<Phase>({ kind: 'idle' });
  const [tempFingerprint, setTempFingerprint] = useState<string | null>(null);
  const [copyHit, setCopyHit] = useState(false);
  const guardianList = useMemo(() => [...props.guardians], [props.guardians]);

  useEffect(() => {
    let cancelled = false;
    void (async () => {
      try {
        const fp = await runtime.fingerprint;
        if (!cancelled) setTempFingerprint(fp);
      } catch {
        if (!cancelled) setTempFingerprint(null);
      }
    })();
    return () => {
      cancelled = true;
    };
  }, [runtime]);

  const start = async (): Promise<void> => {
    setPhase({ kind: 'running', progress: null });
    try {
      const result = await requestRecovery({
        shade: runtime,
        originalAddress: props.originalAddress,
        setupId: props.setupId,
        threshold: props.threshold,
        guardians: guardianList,
        deliver: props.deliver,
        ...(props.timeoutMs !== undefined ? { timeoutMs: props.timeoutMs } : {}),
        onProgress: (progress) => setPhase({ kind: 'running', progress }),
      });
      setPhase({ kind: 'done', result });
      props.onComplete?.(result);
    } catch (err) {
      setPhase({ kind: 'failed', error: err as Error });
      props.onError?.(err as Error);
    }
  };

  const copyOob = async (): Promise<void> => {
    if (tempFingerprint === null) return;
    if (typeof navigator !== 'undefined' && navigator.clipboard?.writeText !== undefined) {
      const text = formatOobText(runtime.myAddress, tempFingerprint);
      await navigator.clipboard.writeText(text);
      setCopyHit(true);
      setTimeout(() => setCopyHit(false), 1500);
    }
  };

  return (
    <div
      style={{
        background: theme.bgElevated,
        border: `1px solid ${theme.border}`,
        borderRadius: theme.radius,
        padding: 16,
        color: theme.text,
        fontFamily: theme.font,
      }}
    >
      <div style={{ fontSize: 14, fontWeight: 600, marginBottom: 8 }}>
        Recover identity for {props.originalAddress}
      </div>
      <div style={{ fontSize: 12, color: theme.textMuted, marginBottom: 10 }}>
        Read the safety number below to each guardian over a side channel (call, in person)
        BEFORE asking them to approve. They will only release their share if your fingerprint
        matches what they verify.
      </div>

      <div
        style={{
          padding: 10,
          borderRadius: 6,
          border: `1px solid ${theme.border}`,
          background: theme.bg,
          fontFamily: theme.fontMono,
          fontSize: 12,
          marginBottom: 10,
          whiteSpace: 'pre-wrap',
        }}
      >
        {tempFingerprint ?? 'Loading temporary fingerprint…'}
      </div>

      <div style={{ display: 'flex', gap: 8, marginBottom: 12 }}>
        <button
          type="button"
          onClick={() => void copyOob()}
          disabled={tempFingerprint === null}
          style={{
            background: 'transparent',
            color: theme.text,
            border: `1px solid ${theme.border}`,
            borderRadius: 6,
            padding: '6px 10px',
            fontSize: 12,
            cursor: tempFingerprint === null ? 'not-allowed' : 'pointer',
          }}
        >
          {copyHit ? 'Copied!' : 'Copy OOB text'}
        </button>
        <button
          type="button"
          disabled={phase.kind === 'running' || tempFingerprint === null}
          onClick={() => void start()}
          style={{
            background: theme.accent,
            color: theme.bg,
            border: `1px solid ${theme.accent}`,
            borderRadius: 6,
            padding: '6px 12px',
            fontSize: 12,
            fontWeight: 600,
            cursor: phase.kind === 'running' ? 'not-allowed' : 'pointer',
            opacity: phase.kind === 'running' ? 0.5 : 1,
          }}
        >
          {phase.kind === 'running' ? 'Requesting…' : 'Request recovery'}
        </button>
      </div>

      {phase.kind === 'running' && phase.progress !== null && (
        <ProgressLine progress={phase.progress} theme={theme} />
      )}

      {phase.kind === 'done' && (
        <div
          style={{
            padding: 10,
            borderRadius: 6,
            border: `1px solid ${theme.success}`,
            background: 'rgba(34, 197, 94, 0.08)',
            color: theme.text,
            fontSize: 12,
          }}
        >
          <div style={{ fontWeight: 600, color: theme.success, marginBottom: 4 }}>
            ✓ Identity restored
          </div>
          <div>
            Restored fingerprint:
            <div
              style={{
                fontFamily: theme.fontMono,
                fontSize: 12,
                marginTop: 4,
                whiteSpace: 'pre-wrap',
              }}
            >
              {phase.result.restoredFingerprint}
            </div>
          </div>
          <div style={{ marginTop: 4, fontSize: 11, color: theme.textMuted }}>
            Compare this against the value on your recovery card before continuing.
          </div>
        </div>
      )}

      {phase.kind === 'failed' && (
        <div
          style={{
            padding: 10,
            borderRadius: 6,
            border: `1px solid ${theme.danger}`,
            background: 'rgba(239, 68, 68, 0.08)',
            color: theme.danger,
            fontSize: 12,
          }}
        >
          <div style={{ fontWeight: 600, marginBottom: 4 }}>
            {failureHeadline(phase.error)}
          </div>
          <div style={{ color: theme.text, fontSize: 11 }}>{phase.error.message}</div>
        </div>
      )}
    </div>
  );
}

function ProgressLine(props: {
  progress: RecoveryProgress;
  theme: ReturnType<typeof useShadeRuntimeTheme>;
}): React.ReactElement {
  const { progress, theme } = props;
  return (
    <div
      style={{
        padding: 10,
        borderRadius: 6,
        border: `1px solid ${theme.border}`,
        background: theme.bg,
        fontSize: 12,
        color: theme.text,
      }}
    >
      <div>
        Granted: {progress.granted} / {progress.threshold} • Declined: {progress.declined} •
        Pending: {progress.pending}
      </div>
      {progress.fromAddress !== undefined && (
        <div style={{ color: theme.textMuted, fontSize: 11, marginTop: 4 }}>
          {progress.fromAddress}: {progress.latest === 'grant' ? 'granted' : 'declined'}
        </div>
      )}
    </div>
  );
}

function failureHeadline(err: Error): string {
  if (err instanceof RecoveryDeclinedError) return 'Too many guardians declined';
  if (err instanceof RecoveryTimeoutError) return 'Timed out waiting for guardians';
  if (err instanceof RecoveryReconstructionError)
    return 'Reconstruction failed — at least one share is invalid';
  return 'Recovery failed';
}
