import { useState, type CSSProperties, type JSX } from 'react';
import { appStore } from '../../store';
import {
  exportToBase64,
  importFromBase64,
  listSnapshots,
  wrap,
  unwrap,
  migrate,
  CURRENT_SCHEMA_VERSION,
  buildPayloadFromStore,
  hydrateStoreFromPayload,
  type V1Payload,
} from '../../save';
import { uiStrings } from '../../content';

/**
 * Settings overlay (CONTEXT D-28). Phase 2 ships save-management surfaces
 * only — Export to Base64 (CORE-09), Import from Base64 (CORE-09), Restore
 * previous snapshot (CORE-08). Audio sliders + keyboard nav + a11y polish
 * land in Phase 8 (UX-04, UX-06, UX-07, UX-08).
 *
 * Per BLOCKER 2 (PLAN W2): the Import path runs the documented pipeline
 * `importFromBase64 → unwrap (CRC verify) → migrate`. Skipping unwrap or
 * migrate would silently accept any future-shape payload as the current
 * shape; this code goes through both.
 *
 * Player-visible strings come from /content/seasons/01-soil/ui-strings.yaml
 * (CLAUDE.md externalized-strings rule). Status-line copy (`'Saved to
 * clipboard.'`, `'Restored.'`, etc.) is intentionally inline as a
 * Phase-2 minimum-viable choice — Phase 8 moves these into uiStrings if
 * tone review demands it.
 */
export function Settings({
  open,
  onClose,
}: {
  open: boolean;
  onClose: () => void;
}): JSX.Element | null {
  const strings = uiStrings[1]?.settings;
  const [base64Buf, setBase64Buf] = useState('');
  const [statusLine, setStatusLine] = useState<string | null>(null);
  if (!open || !strings) return null;

  const onExport = (): void => {
    try {
      const state = appStore.getState();
      // W2 — shared two-arg signature. Settings has no clock injection
      // on hand; pass Date.now() for the wall-clock anchor (BLOCKER 3:
      // lastTickAt is wall-clock ms, owned by the application layer).
      const payload: V1Payload = buildPayloadFromStore(state, Date.now());
      const env = wrap(payload, CURRENT_SCHEMA_VERSION);
      const b64 = exportToBase64(env);
      void navigator.clipboard?.writeText(b64).catch(() => {
        /* clipboard API may be unavailable; the textarea still has the value */
      });
      setBase64Buf(b64);
      setStatusLine('Saved to clipboard.');
    } catch {
      setStatusLine('Could not save.');
    }
  };

  const onImport = (): void => {
    try {
      // BLOCKER 2 — full pipeline: importFromBase64 (decompress + Zod
      // validate envelope shape) → unwrap (CRC verify; throws
      // SaveCorruptError on mismatch) → migrate (chain forward to
      // CURRENT_SCHEMA_VERSION).
      const env = importFromBase64(base64Buf);
      const raw = unwrap(env);
      const result = migrate(raw, env.schemaVersion);
      hydrateStoreFromPayload(appStore.getState(), result.payload as V1Payload);
      setStatusLine('Restored.');
    } catch {
      setStatusLine("That doesn't look like one of yours.");
    }
  };

  const onRestoreSnapshot = (): void => {
    void (async () => {
      try {
        const snaps = await listSnapshots();
        if (snaps.length === 0) {
          setStatusLine('Nothing earlier to find.');
          return;
        }
        // listSnapshots returns newest-first; restore the most recent.
        const latest = snaps[0];
        if (!latest) {
          setStatusLine('Nothing earlier to find.');
          return;
        }
        const raw = unwrap(latest.envelope);
        const result = migrate(raw, latest.envelope.schemaVersion);
        hydrateStoreFromPayload(
          appStore.getState(),
          result.payload as V1Payload,
        );
        setStatusLine('Earlier garden restored.');
      } catch {
        setStatusLine('Nothing earlier could be reached.');
      }
    })();
  };

  return (
    <div
      role="dialog"
      aria-label={strings.title}
      data-testid="settings-modal"
      style={{
        position: 'fixed',
        inset: 0,
        zIndex: 70,
        background: '#1a1a1ac0',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
        color: '#e8e0d0',
        fontFamily: 'serif',
      }}
    >
      <div
        style={{
          maxWidth: 520,
          background: '#1f1f23',
          padding: '2rem',
          borderRadius: 4,
        }}
      >
        <h2
          style={{
            marginTop: 0,
            fontWeight: 300,
            letterSpacing: '0.1em',
          }}
        >
          {strings.title}
        </h2>
        <button data-testid="settings-export" onClick={onExport} style={btnStyle}>
          {strings.export}
        </button>
        <textarea
          value={base64Buf}
          onChange={(e) => setBase64Buf(e.target.value)}
          rows={4}
          style={{
            width: '100%',
            marginTop: '1rem',
            fontFamily: 'monospace',
            fontSize: '0.8rem',
          }}
          aria-label="Save data"
        />
        <button data-testid="settings-import" onClick={onImport} style={btnStyle}>
          {strings.import}
        </button>
        <button
          data-testid="settings-restore"
          onClick={onRestoreSnapshot}
          style={btnStyle}
        >
          {strings.restore_snapshot}
        </button>
        {statusLine && (
          <p style={{ opacity: 0.6, fontStyle: 'italic' }}>{statusLine}</p>
        )}
        <button
          data-testid="settings-close"
          onClick={onClose}
          style={{ ...btnStyle, marginTop: '1.5rem' }}
        >
          Close
        </button>
      </div>
    </div>
  );
}

const btnStyle: CSSProperties = {
  display: 'block',
  margin: '0.5rem 0',
  padding: '0.5rem 1rem',
  background: 'transparent',
  color: '#e8e0d0',
  border: '1px solid #4d4d52',
  cursor: 'pointer',
  fontFamily: 'serif',
  textAlign: 'left',
  width: '100%',
};
