'use client';

import React, { useCallback, useEffect, useMemo, useState } from 'react';
import toast from 'react-hot-toast';
import {
  FiCheckCircle,
  FiUpload,
  FiFileText,
  FiImage,
  FiCheck,
  FiX,
  FiLock,
  FiAlertCircle,
  FiCalendar,
  FiUser,
  FiPaperclip,
} from 'react-icons/fi';
import {
  getNcClosure,
  saveNcClosure,
  fetchClosureFileBlob,
} from '@/lib/api/previous-nc.api';
import type {
  ClosureResponse,
  ClosureRow,
  NcSource,
} from '@/lib/api/types/previous-nc.types';
import type { EditableEntry } from './findings.types';
import { isDraft } from './findings.types';
import ClosureFindingPicker from './ClosureFindingPicker';
import ClosureVerificationTable from './ClosureVerificationTable';

// ═══════════════════════════════════════════════════════════════════════
// 🆕 PHASE 2A — Closure Panel (main component)
// ═══════════════════════════════════════════════════════════════════════
// Lives at the bottom of NcEditPage, between NC closure & tracking and
// Email notifications. Auditor uses this to verify and close findings.
// ═══════════════════════════════════════════════════════════════════════

interface Props {
  source: NcSource;
  ncId: number;
  entries: EditableEntry[];
  /** Called after a finalize so parent can refetch */
  onFinalized?: () => void;
}

const SIGNED_COPY_EXTS = ['.pdf', '.doc', '.docx'];
const SIGNATURE_EXTS = ['.png', '.jpg', '.jpeg', '.webp'];
const MAX_SIGNED_COPY = 50 * 1024 * 1024;
const MAX_SIGNATURE = 5 * 1024 * 1024;

export default function ClosurePanel({
  source,
  ncId,
  entries,
  onFinalized,
}: Props) {
  const [loading, setLoading] = useState(true);
  const [closure, setClosure] = useState<ClosureResponse | null>(null);

  // Selection + per-row state
  const [selectedIds, setSelectedIds] = useState<Set<number>>(new Set());
  const [rows, setRows] = useState<ClosureRow[]>([]);
  const [verification, setVerification] = useState('');
  const [auditorName, setAuditorName] = useState('');
  const [closureDate, setClosureDate] = useState('');
  const [sendToClient, setSendToClient] = useState(false);

  // File state
  const [signedCopyFile, setSignedCopyFile] = useState<File | null>(null);
  const [signatureFile, setSignatureFile] = useState<File | null>(null);
  const [signaturePreview, setSignaturePreview] = useState<string | null>(null);

  // Save state
  const [saving, setSaving] = useState(false);
  const [savingProgress, setSavingProgress] = useState(0);
  const [editMode, setEditMode] = useState(false);   // 🆕 edit a finalized closure

  // ─── Fetch existing closure ────────────────────────────────────────
  const fetchClosure = useCallback(async () => {
    setLoading(true);
    try {
      const data = await getNcClosure(source, ncId);
      setClosure(data);

      // Pre-fill from existing data if any
      if (data.rows.length > 0) {
        setSelectedIds(new Set(data.rows.map((r) => r.entry_id)));
        setRows(
          data.rows.map((r) => ({
            entry_id: r.entry_id,
            evidence_received: r.evidence_received,
            submitted_docs: r.submitted_docs,
            result_accepted: r.result_accepted,
            remarks: r.remarks,
          })),
        );
      }
      setVerification(data.verification_by_auditor || '');
      setAuditorName(data.auditor_name || '');
      setClosureDate(data.closure_date || todayDateString());
      setSendToClient(data.send_to_client);
    } catch (err: any) {
      console.error('Failed to load closure', err);
      // Soft-fail — initialize defaults so panel still works
      setClosure({
        nc_id: ncId,
        source,
        is_finalized: false,
        finalized_at: null,
        signed_copy_path: null,
        signature_path: null,
        verification_by_auditor: '',
        auditor_name: '',
        closure_date: null,
        send_to_client: false,
        rows: [],
      });
      setClosureDate(todayDateString());
    } finally {
      setLoading(false);
    }
  }, [source, ncId]);

  useEffect(() => {
    fetchClosure();
  }, [fetchClosure]);

  const isFinalized = !!closure?.is_finalized;
  // 🆕 Panel is only locked when finalized AND the user hasn't opted into editing.
  const locked = isFinalized && !editMode;
  const [closureTo, setClosureTo] = useState('');
  const [closureCc, setClosureCc] = useState('');   // 🆕
  const [closureBcc, setClosureBcc] = useState(''); // 🆕
    const [sendingEmail, setSendingEmail] = useState(false); // 🆕
  // 🆕 PHASE 2B — track the last generated merged PDF info (from save response)
  const [lastMergedSha256, setLastMergedSha256] = useState<string | null>(null);
  const [lastMergedPages, setLastMergedPages] = useState<number | null>(null);
  const acceptedCount = useMemo(
    () =>
      rows.filter((r) => selectedIds.has(r.entry_id) && r.result_accepted)
        .length,
    [rows, selectedIds],
  );

  // ─── Toggle selection ──────────────────────────────────────────────
  const handleToggle = useCallback((id: number) => {
    setSelectedIds((prev) => {
      const next = new Set(prev);
      if (next.has(id)) {
        next.delete(id);
      } else {
        next.add(id);
      }
      return next;
    });
    // Ensure a row exists for this id
    setRows((prev) => {
      if (prev.find((r) => r.entry_id === id)) return prev;
      return [
        ...prev,
        {
          entry_id: id,
          evidence_received: '',
          submitted_docs: '',
          result_accepted: false,
          remarks: '',
        },
      ];
    });
  }, []);

  const handleSelectAll = useCallback(() => {
    const openEntries = entries.filter(
      (e) => !isDraft(e) && e.status !== 'closed',
    );
    const allSelected = openEntries.every((e) => selectedIds.has(e.id));
    if (allSelected) {
      setSelectedIds(new Set());
    } else {
      setSelectedIds(new Set(openEntries.map((e) => e.id)));
      setRows((prev) => {
        const existing = new Map(prev.map((r) => [r.entry_id, r]));
        openEntries.forEach((e) => {
          if (!existing.has(e.id)) {
            existing.set(e.id, {
              entry_id: e.id,
              evidence_received: '',
              submitted_docs: '',
              result_accepted: false,
              remarks: '',
            });
          }
        });
        return Array.from(existing.values());
      });
    }
  }, [entries, selectedIds]);

  // ─── Row updates ───────────────────────────────────────────────────
  const handleRowChange = useCallback(
    (entryId: number, patch: Partial<ClosureRow>) => {
      setRows((prev) =>
        prev.map((r) =>
          r.entry_id === entryId ? { ...r, ...patch } : r,
        ),
      );
    },
    [],
  );

  // ─── File handlers ─────────────────────────────────────────────────
  const handleSignedCopy = useCallback((file: File) => {
    const ext = ('.' + (file.name.split('.').pop() || '')).toLowerCase();
    if (!SIGNED_COPY_EXTS.includes(ext)) {
      toast.error(`Signed copy must be PDF, DOC, or DOCX`);
      return;
    }
    if (file.size > MAX_SIGNED_COPY) {
      toast.error(`File too large. Max 50 MB.`);
      return;
    }
    setSignedCopyFile(file);
    toast.success(`Signed copy ready: ${file.name}`);
  }, []);

  const handleSignature = useCallback((file: File) => {
    const ext = ('.' + (file.name.split('.').pop() || '')).toLowerCase();
    if (!SIGNATURE_EXTS.includes(ext)) {
      toast.error(`Signature must be PNG, JPG, or WEBP`);
      return;
    }
    if (file.size > MAX_SIGNATURE) {
      toast.error(`Signature too large. Max 5 MB.`);
      return;
    }
    setSignatureFile(file);
    // Preview
    const reader = new FileReader();
    reader.onload = () => setSignaturePreview(reader.result as string);
    reader.readAsDataURL(file);
    toast.success(`Signature ready: ${file.name}`);
  }, []);

  // ─── View existing signed copy ─────────────────────────────────────
  const openExistingSignedCopy = useCallback(async () => {
    try {
      const url = await fetchClosureFileBlob(source, ncId, 'signed_copy');
      const win = window.open(url, '_blank');
      if (!win) toast.error('Popup blocked');
      setTimeout(() => URL.revokeObjectURL(url), 60_000);
    } catch (err: any) {
      toast.error(err?.message ?? 'Failed to open signed copy');
    }
  }, [source, ncId]);

  // ─── Save / Finalize ───────────────────────────────────────────────
  const handleSave = async (finalize: boolean) => {
    if (selectedIds.size === 0) {
      toast.error('Select at least one finding to close');
      return;
    }
    if (finalize) {
      if (!auditorName.trim()) {
        toast.error('Auditor name is required to finalize');
        return;
      }
      if (!closureDate) {
        toast.error('Closure date is required to finalize');
        return;
      }
      // Require either existing signed copy or new upload
      if (!closure?.signed_copy_path && !signedCopyFile) {
        toast.error('Client-signed copy is required to finalize');
        return;
      }
      const ok = window.confirm(
        `Finalize closure for ${selectedIds.size} finding(s)?\n\n` +
        `• ${acceptedCount} marked Accepted → will be Closed\n` +
        `• ${selectedIds.size - acceptedCount} marked Not Accepted → stay Open\n\n` +
        `This cannot be undone without reopening the NC.`,
      );
      if (!ok) return;
    }

    setSaving(true);
    setSavingProgress(0);
    try {
      const payload = {
        closed_entry_ids: Array.from(selectedIds),
        rows: rows.filter((r) => selectedIds.has(r.entry_id)),
        verification_by_auditor: verification,
        auditor_name: auditorName,
        closure_date: closureDate,
        send_to_client: sendToClient,
        closure_to: closureTo.trim() || undefined,    // 🆕
        closure_cc: closureCc.trim() || undefined,    // 🆕
        closure_bcc: closureBcc.trim() || undefined,  // 🆕
        finalize,
        signed_copy: signedCopyFile || undefined,
        signature: signatureFile || undefined,
      };
      const res = await saveNcClosure(source, ncId, payload, (pct) =>
        setSavingProgress(pct),
      );

      // 🆕 PHASE 2B — capture merged PDF info if returned
      if (res.merged_pdf_sha256) setLastMergedSha256(res.merged_pdf_sha256);
      if (res.merged_pdf_pages) setLastMergedPages(res.merged_pdf_pages);

      toast.success(
        finalize
          ? `Closure finalized — merged PDF created (${res.merged_pdf_pages || '?'} pages)`
          : `Closure draft saved — ${res.rows_saved} row(s)`,
      );
      setSignedCopyFile(null);
      setSignatureFile(null);
      setEditMode(false);
      await fetchClosure();
      if (finalize && onFinalized) onFinalized();
    } catch (err: any) {
      toast.error(err?.response?.data?.message ?? err?.message ?? 'Save failed');
    } finally {
      setSaving(false);
      setSavingProgress(0);
    }
  };
// ─── Standalone "Send now" — emails the finalized PDF to typed To/CC/BCC ───
  const handleSendClosureEmail = async () => {
    if (!closureTo.trim()) {
      toast.error('Enter a "To" address first');
      return;
    }
    if (!isFinalized) {
      toast.error('Finalize the closure first, then send.');
      return;
    }
    setSendingEmail(true);
    try {
      const token =
        localStorage.getItem('access_token') ||
        sessionStorage.getItem('access_token') ||
        localStorage.getItem('token') ||
        '';
      const base =
        process.env.NEXT_PUBLIC_API_URL?.replace(/\/api$/, '') ||
        process.env.NEXT_PUBLIC_API_BASE_URL?.replace(/\/api$/, '') ||
        '';
      const res = await fetch(
        `${base}/api/previous-nc/closures/${source}/${ncId}/send-email`,
        {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            Authorization: token ? `Bearer ${token}` : '',
          },
          body: JSON.stringify({
            closure_to: closureTo.trim(),
            closure_cc: closureCc.trim() || undefined,
            closure_bcc: closureBcc.trim() || undefined,
          }),
        },
      );
      if (!res.ok) {
        const b = await res.json().catch(() => ({}));
        throw new Error(b?.message || `Failed (${res.status})`);
      }
      const out = await res.json();
      toast.success(`Email sent to ${out.sent_to}`);
    } catch (err: any) {
      toast.error(err?.message ?? 'Failed to send email');
    } finally {
      setSendingEmail(false);
    }
  };
  if (loading) {
    return (
      <div
        style={{
          padding: '40px 18px',
          textAlign: 'center',
          background: '#fff',
          border: '1px solid #e2e8f0',
          borderRadius: 12,
          marginBottom: 12,
          color: '#94a3b8',
          fontSize: 12,
        }}
      >
        Loading closure data…
      </div>
    );
  }

  return (
    <div
      style={{
        background: '#fff',
        border: '1px solid #e2e8f0',
        borderRadius: 12,
        overflow: 'hidden',
        marginBottom: 12,
      }}
    >
      {/* ── Header ── */}
      <div
        style={{
          padding: '14px 18px',
          borderBottom: '1px solid #f1f5f9',
          background: isFinalized
            ? 'linear-gradient(180deg, #f0fdf4 0%, #fff 100%)'
            : 'linear-gradient(180deg, #fafbfc 0%, #fff 100%)',
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'space-between',
          gap: 12,
          flexWrap: 'wrap',
        }}
      >
        <div style={{ display: 'flex', alignItems: 'center', gap: 11 }}>
          <div
            style={{
              width: 34,
              height: 34,
              background: isFinalized
                ? 'linear-gradient(135deg, #15803d, #0F6E56)'
                : 'linear-gradient(135deg, #185FA5, #0C447C)',
              borderRadius: 8,
              display: 'inline-flex',
              alignItems: 'center',
              justifyContent: 'center',
            }}
          >
            <FiCheckCircle size={17} color="#fff" />
          </div>
          <div>
            <div style={{ fontSize: 14, fontWeight: 700, color: '#0b1220' }}>
              Final closure & verification
            </div>
            <div
              style={{
                fontSize: 11,
                color: '#64748b',
                marginTop: 2,
              }}
            >
              {isFinalized
                ? 'This closure has been finalized'
                : 'Upload signed copy, fill verification, finalize when ready'}
            </div>
          </div>
        </div>
        {isFinalized && (
          <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
            <span
              style={{
                fontSize: 10,
                padding: '4px 10px',
                background: '#dcfce7',
                color: '#15803d',
                borderRadius: 99,
                fontWeight: 700,
                letterSpacing: '0.06em',
                display: 'inline-flex',
                alignItems: 'center',
                gap: 5,
              }}
            >
              <FiLock size={11} />
              FINALIZED
            </span>
            <button
              type="button"
              onClick={() => setEditMode((v) => !v)}
              style={{
                fontSize: 11,
                padding: '5px 12px',
                background: editMode ? '#185FA5' : '#fff',
                color: editMode ? '#fff' : '#185FA5',
                border: '1px solid #185FA5',
                borderRadius: 7,
                fontWeight: 700,
                cursor: 'pointer',
              }}
            >
              {editMode ? 'Cancel edit' : 'Edit closure'}
            </button>
          </div>
        )}
      </div>

      {/* ── Body ── */}
      <div style={{ padding: '18px' }}>
        {isFinalized && (
          <div
            style={{
              marginBottom: 16,
              padding: '11px 14px',
              background: '#f0fdf4',
              border: '1px solid #bbf7d0',
              borderRadius: 8,
              fontSize: 12,
              color: '#15803d',
              display: 'flex',
              alignItems: 'center',
              gap: 8,
            }}
          >
            <FiLock size={14} />
            <span>
              Closure was finalized on{' '}
              <strong>{formatDate(closure?.finalized_at)}</strong>. To make
              further changes, reopen the NC first.
            </span>
          </div>
        )}

        {/* ─── 1. Finding picker ─── */}
        <div style={{ marginBottom: 22 }}>
          <ClosureFindingPicker
            entries={entries}
            selectedIds={selectedIds}
            onToggle={locked ? () => null : handleToggle}
            onSelectAll={locked ? () => null : handleSelectAll}
          />
        </div>

        {/* ─── 2. Verification table (only if findings ticked) ─── */}
        {selectedIds.size > 0 && (
          <div style={{ marginBottom: 22 }}>
            <ClosureVerificationTable
              entries={entries}
              selectedIds={selectedIds}
              rows={rows}
              onRowChange={handleRowChange}
              disabled={locked}
            />
          </div>
        )}

        {/* ─── 3. Verification textarea ─── */}
        {selectedIds.size > 0 && (
          <div style={{ marginBottom: 18 }}>
            <Label>Verification by auditor (applies to all rows above)</Label>
            <textarea
              value={verification}
              onChange={(e) => setVerification(e.target.value)}
              placeholder="Overall verification comment from the auditor…"
              rows={3}
              disabled={locked}
              style={{
                ...inputStyle(),
                height: 'auto',
                paddingTop: 9,
                resize: 'vertical',
                lineHeight: 1.55,
                fontFamily: 'inherit',
              }}
            />
          </div>
        )}

        {/* ─── 4. Signed copy upload ─── */}
        <div style={{ marginBottom: 18 }}>
          <div
            style={{
              display: 'flex',
              alignItems: 'center',
              gap: 8,
              marginBottom: 8,
            }}
          >
            <FiPaperclip size={13} color="#64748b" />
            <Label inline>Client-signed copy</Label>
            <span
              style={{
                fontSize: 9,
                padding: '1px 6px',
                background: '#FCEBEB',
                color: '#A32D2D',
                borderRadius: 4,
                fontWeight: 700,
                letterSpacing: '0.04em',
              }}
            >
              REQUIRED TO FINALIZE
            </span>
            <span
              style={{
                fontSize: 10,
                color: '#94a3b8',
                marginLeft: 'auto',
              }}
            >
              PDF, DOC, DOCX · max 50 MB
            </span>
          </div>

          {closure?.signed_copy_path && !signedCopyFile && (
            <div
              style={{
                display: 'flex',
                alignItems: 'center',
                gap: 10,
                padding: '10px 12px',
                background: isFinalized ? '#eef2ff' : '#f0fdf4',
                border: `1px solid ${isFinalized ? '#c7d2fe' : '#bbf7d0'}`,
                borderRadius: 8,
                marginBottom: 8,
              }}
            >
              <FiFileText size={18} color={isFinalized ? '#4338ca' : '#15803d'} />
              <div style={{ flex: 1, minWidth: 0 }}>
                <div
                  style={{
                    fontSize: 12,
                    color: '#0b1220',
                    fontWeight: isFinalized ? 600 : 500,
                  }}
                >
                  {isFinalized
                    ? 'Final merged closure PDF'
                    : 'Current signed copy uploaded'}
                </div>
                {isFinalized && (
                  <div
                    style={{
                      fontSize: 10,
                      color: '#64748b',
                      marginTop: 2,
                      display: 'flex',
                      gap: 10,
                      flexWrap: 'wrap',
                    }}
                  >
                    <span>
                      Verification page + client signed copy, merged
                    </span>
                    {lastMergedPages && (
                      <span>· {lastMergedPages} pages</span>
                    )}
                  </div>
                )}
              </div>
              <button
                type="button"
                onClick={openExistingSignedCopy}
                style={btnSecondary()}
              >
                {isFinalized ? 'View merged PDF' : 'Open'}
              </button>
            </div>
          )}

          {/* 🆕 PHASE 2B — SHA-256 tamper-detection display */}
          {isFinalized && lastMergedSha256 && (
            <div
              style={{
                padding: '8px 12px',
                background: '#fafbfc',
                border: '1px solid #e2e8f0',
                borderRadius: 8,
                marginBottom: 8,
                fontSize: 10,
                color: '#475569',
                fontFamily: "'JetBrains Mono', monospace",
              }}
            >
              <div
                style={{
                  display: 'flex',
                  alignItems: 'center',
                  gap: 6,
                  marginBottom: 3,
                }}
              >
                <FiLock size={11} color="#0F6E56" />
                <span
                  style={{
                    fontFamily:
                      "Inter, -apple-system, BlinkMacSystemFont, sans-serif",
                    fontWeight: 700,
                    color: '#0F6E56',
                    fontSize: 10,
                    letterSpacing: '0.06em',
                    textTransform: 'uppercase',
                  }}
                >
                  SHA-256 tamper hash
                </span>
              </div>
              <div
                style={{
                  wordBreak: 'break-all',
                  color: '#334155',
                  lineHeight: 1.5,
                }}
                title={lastMergedSha256}
              >
                {lastMergedSha256}
              </div>
            </div>
          )}

          <FileDropZone
            file={signedCopyFile}
            accept={SIGNED_COPY_EXTS.join(',')}
            onChoose={handleSignedCopy}
            onClear={() => setSignedCopyFile(null)}
            placeholder={
              closure?.signed_copy_path
                ? 'Drop new file to replace, or click to browse'
                : 'Drag a file or click to browse'
            }
            disabled={locked}
          />
        </div>

        {/* ─── 5. Auditor name, signature, date ─── */}
        <div
          style={{
            display: 'grid',
            gridTemplateColumns: '1.5fr 1fr 1fr',
            gap: 12,
            marginBottom: 18,
          }}
        >
          <div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 5 }}>
              <FiUser size={11} color="#64748b" />
              <Label inline>Auditor name</Label>
            </div>
            <input
              value={auditorName}
              onChange={(e) => setAuditorName(e.target.value)}
              placeholder="e.g. Glenda Sol"
              disabled={isFinalized}
              style={inputStyle()}
            />
          </div>
          <div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 5 }}>
              <FiImage size={11} color="#64748b" />
              <Label inline>Signature image</Label>
            </div>
            <SignatureUpload
              file={signatureFile}
              preview={signaturePreview}
              hasExisting={!!closure?.signature_path}
              onChoose={handleSignature}
              onClear={() => {
                setSignatureFile(null);
                setSignaturePreview(null);
              }}
              disabled={locked}
            />
          </div>
          <div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 5 }}>
              <FiCalendar size={11} color="#64748b" />
              <Label inline>Date of closure</Label>
            </div>
            <input
              type="date"
              value={closureDate}
              onChange={(e) => setClosureDate(e.target.value)}
              disabled={locked}
              style={inputStyle()}
            />
          </div>
        </div>

        {/* ─── 6. Send-to-client checkbox ─── */}
        {!locked && (
          <div
            style={{
              padding: '11px 14px',
              background: '#fafbfc',
              border: '1px solid #e2e8f0',
              borderRadius: 8,
              marginBottom: 18,
              display: 'flex',
              alignItems: 'center',
              justifyContent: 'space-between',
              flexWrap: 'wrap',
              gap: 12,
            }}
          >
            <div
              role="checkbox"
              aria-checked={sendToClient}
              tabIndex={0}
              onClick={() => setSendToClient(!sendToClient)}
              onKeyDown={(ev) => {
                if (ev.key === ' ' || ev.key === 'Enter') {
                  ev.preventDefault();
                  setSendToClient(!sendToClient);
                }
              }}
              style={{
                display: 'inline-flex',
                alignItems: 'center',
                gap: 9,
                fontSize: 12,
                color: '#475569',
                cursor: 'pointer',
                userSelect: 'none',
                outline: 'none',
              }}
            >
              <span
                style={{
                  display: 'inline-flex',
                  alignItems: 'center',
                  justifyContent: 'center',
                  width: 16,
                  height: 16,
                  background: sendToClient ? '#185FA5' : '#fff',
                  border: `1.5px solid ${sendToClient ? '#185FA5' : '#cbd5e1'}`,
                  borderRadius: 4,
                  transition: 'all 0.12s',
                }}
              >
                {sendToClient && <FiCheck size={11} color="#fff" />}
              </span>
              Send final closure to{' '}
              <strong style={{ color: '#0b1220' }}>
                Client & Coordinator
              </strong>{' '}
              after finalize
            </div>
            <span
              style={{
                fontSize: 10,
                color: '#15803d',
                padding: '2px 7px',
                background: '#dcfce7',
                borderRadius: 99,
                fontWeight: 600,
                display: 'inline-flex',
                alignItems: 'center',
                gap: 4,
              }}
            >
              <FiCheck size={10} />
              Sends Final closure to client/Cordinator
            </span>
            {sendToClient && (
              <div style={{ width: '100%', marginTop: 12 }}>
                <div
                  style={{
                    display: 'grid',
                    gridTemplateColumns: 'repeat(3, 1fr)',
                    gap: 12,
                  }}
                >
                  <div>
                    <Label inline>To (Client email)</Label>
                    <input
                      value={closureTo}
                      onChange={(e) => setClosureTo(e.target.value)}
                      placeholder="client@example.com"
                      disabled={locked}
                      style={{ ...inputStyle(), marginTop: 5 }}
                    />
                  </div>
                  <div>
                    <Label inline>CC</Label>
                    <input
                      value={closureCc}
                      onChange={(e) => setClosureCc(e.target.value)}
                      placeholder="cc@example.com"
                      disabled={locked}
                      style={{ ...inputStyle(), marginTop: 5 }}
                    />
                  </div>
                  <div>
                    <Label inline>BCC</Label>
                    <input
                      value={closureBcc}
                      onChange={(e) => setClosureBcc(e.target.value)}
                      placeholder="bcc@example.com"
                      disabled={locked}
                      style={{ ...inputStyle(), marginTop: 5 }}
                    />
                  </div>
                </div>
                <div
                  style={{
                    fontSize: 10,
                    color: '#94a3b8',
                    marginTop: 8,
                    display: 'inline-flex',
                    alignItems: 'center',
                    gap: 5,
                  }}
                >
                  <FiAlertCircle size={10} /> Enter at least one “To” address.
                  Email sends only to what you type — never to the client by
                  default. Separate multiple recipients with a comma.
                </div>

                <div
                  style={{
                    display: 'flex',
                    justifyContent: 'flex-end',
                    marginTop: 10,
                  }}
                >
                  <button
                    type="button"
                    onClick={handleSendClosureEmail}
                    disabled={sendingEmail || !closureTo.trim() || !isFinalized}
                    title={
                      !isFinalized
                        ? 'Finalize the closure first'
                        : !closureTo.trim()
                          ? 'Enter a "To" address'
                          : 'Send the finalized PDF now'
                    }
                    style={{
                      padding: '8px 16px',
                      background: sendingEmail ? '#94a3b8' : '#185FA5',
                      color: '#fff',
                      border: 'none',
                      borderRadius: 7,
                      fontSize: 12,
                      fontWeight: 700,
                      cursor:
                        sendingEmail || !closureTo.trim() || !isFinalized
                          ? 'not-allowed'
                          : 'pointer',
                      display: 'inline-flex',
                      alignItems: 'center',
                      gap: 6,
                      opacity:
                        !closureTo.trim() || !isFinalized ? 0.5 : 1,
                    }}
                  >
                    <FiCheck size={13} />
                    {sendingEmail ? 'Sending…' : 'Send now'}
                  </button>
                </div>
              </div>
            )}
          </div>
        )}

        {/* ─── 7. Action buttons ─── */}
        {!locked && (
          <div
            style={{
              display: 'flex',
              gap: 8,
              justifyContent: 'flex-end',
              paddingTop: 14,
              borderTop: '1px dashed #e2e8f0',
              flexWrap: 'wrap',
            }}
          >
            <div
              style={{
                marginRight: 'auto',
                fontSize: 11,
                color: '#64748b',
                display: 'flex',
                alignItems: 'center',
                gap: 6,
              }}
            >
              {selectedIds.size > 0 && (
                <>
                  <FiCheck size={12} color="#15803d" />
                  <span>
                    {selectedIds.size} selected ·{' '}
                    <strong style={{ color: '#15803d' }}>
                      {acceptedCount} accepted
                    </strong>{' '}
                    ·{' '}
                    <strong style={{ color: '#A32D2D' }}>
                      {selectedIds.size - acceptedCount} not accepted
                    </strong>
                  </span>
                </>
              )}
            </div>
            <button
              type="button"
              onClick={() => handleSave(false)}
              disabled={saving || selectedIds.size === 0}
              style={btnSecondary(saving || selectedIds.size === 0)}
            >
              {saving && savingProgress > 0
                ? `Saving… ${savingProgress}%`
                : 'Save draft'}
            </button>
            <button
              type="button"
              onClick={() => handleSave(true)}
              disabled={saving || selectedIds.size === 0}
              style={btnPrimary(saving || selectedIds.size === 0)}
            >
              <FiCheck size={13} />
              Finalize closure
              {selectedIds.size > 0 ? ` (${selectedIds.size})` : ''}
            </button>
          </div>
        )}
      </div>
    </div>
  );
}

// ═══════════════════════════════════════════════════════════════════════
// File drop zones
// ═══════════════════════════════════════════════════════════════════════

function FileDropZone({
  file,
  accept,
  onChoose,
  onClear,
  placeholder,
  disabled,
}: {
  file: File | null;
  accept: string;
  onChoose: (f: File) => void;
  onClear: () => void;
  placeholder: string;
  disabled?: boolean;
}) {
  const [dragOver, setDragOver] = useState(false);

  if (file) {
    return (
      <div
        style={{
          display: 'flex',
          alignItems: 'center',
          gap: 10,
          padding: '11px 14px',
          background: '#f8faff',
          border: '1px solid #185FA5',
          borderRadius: 8,
        }}
      >
        <FiFileText size={18} color="#185FA5" />
        <div style={{ flex: 1, minWidth: 0 }}>
          <div
            style={{
              fontSize: 12,
              fontWeight: 600,
              color: '#0b1220',
              overflow: 'hidden',
              textOverflow: 'ellipsis',
              whiteSpace: 'nowrap',
            }}
          >
            {file.name}
          </div>
          <div
            style={{
              fontSize: 10,
              color: '#94a3b8',
              fontFamily: "'JetBrains Mono', monospace",
              marginTop: 2,
            }}
          >
            {(file.size / 1024 / 1024).toFixed(2)} MB · ready to upload
          </div>
        </div>
        <button
          type="button"
          onClick={onClear}
          disabled={disabled}
          style={{
            background: '#fff',
            border: '1px solid #fecaca',
            borderRadius: 5,
            padding: '5px 9px',
            color: '#dc2626',
            cursor: disabled ? 'not-allowed' : 'pointer',
            fontSize: 11,
            display: 'inline-flex',
            alignItems: 'center',
            gap: 4,
          }}
        >
          <FiX size={11} /> Remove
        </button>
      </div>
    );
  }

  return (
    <label
      onDragEnter={(e) => {
        e.preventDefault();
        if (!disabled) setDragOver(true);
      }}
      onDragOver={(e) => {
        e.preventDefault();
        if (!disabled) setDragOver(true);
      }}
      onDragLeave={(e) => {
        e.preventDefault();
        setDragOver(false);
      }}
      onDrop={(e) => {
        e.preventDefault();
        setDragOver(false);
        if (disabled) return;
        const f = e.dataTransfer.files?.[0];
        if (f) onChoose(f);
      }}
      style={{
        display: 'block',
        padding: '18px 14px',
        border: `1.5px dashed ${dragOver ? '#185FA5' : '#cbd5e1'}`,
        borderRadius: 8,
        background: dragOver ? '#eff6ff' : '#fafbfc',
        textAlign: 'center',
        cursor: disabled ? 'not-allowed' : 'pointer',
        opacity: disabled ? 0.6 : 1,
        transition: 'all 0.15s',
      }}
    >
      <input
        type="file"
        accept={accept}
        disabled={disabled}
        onChange={(e) => {
          const f = e.target.files?.[0];
          if (f) onChoose(f);
        }}
        style={{ display: 'none' }}
      />
      <FiUpload size={20} color={dragOver ? '#185FA5' : '#64748b'} />
      <div
        style={{
          fontSize: 12,
          color: dragOver ? '#185FA5' : '#475569',
          marginTop: 6,
          fontWeight: 500,
        }}
      >
        {placeholder}
      </div>
    </label>
  );
}

function SignatureUpload({
  file,
  preview,
  hasExisting,
  onChoose,
  onClear,
  disabled,
}: {
  file: File | null;
  preview: string | null;
  hasExisting: boolean;
  onChoose: (f: File) => void;
  onClear: () => void;
  disabled?: boolean;
}) {
  if (preview) {
    return (
      <div
        style={{
          display: 'flex',
          alignItems: 'center',
          gap: 8,
          padding: '6px 10px',
          background: '#f8faff',
          border: '1px solid #185FA5',
          borderRadius: 7,
          height: 36,
          boxSizing: 'border-box',
        }}
      >
        <img
          src={preview}
          alt="Signature"
          style={{
            height: 24,
            maxWidth: 80,
            objectFit: 'contain',
          }}
        />
        <span
          style={{
            flex: 1,
            fontSize: 10,
            color: '#185FA5',
            fontWeight: 500,
            overflow: 'hidden',
            textOverflow: 'ellipsis',
            whiteSpace: 'nowrap',
          }}
        >
          {file?.name}
        </span>
        <button
          type="button"
          onClick={onClear}
          disabled={disabled}
          style={{
            background: 'transparent',
            border: 'none',
            color: '#dc2626',
            cursor: disabled ? 'not-allowed' : 'pointer',
            padding: 0,
          }}
        >
          <FiX size={13} />
        </button>
      </div>
    );
  }
  return (
    <label
      style={{
        display: 'flex',
        alignItems: 'center',
        gap: 6,
        padding: '8px 11px',
        height: 36,
        boxSizing: 'border-box',
        fontSize: 11,
        border: '1px dashed #cbd5e1',
        borderRadius: 7,
        background: '#fff',
        cursor: disabled ? 'not-allowed' : 'pointer',
        color: hasExisting ? '#15803d' : '#185FA5',
        fontWeight: 500,
      }}
    >
      <input
        type="file"
        accept=".png,.jpg,.jpeg,.webp"
        disabled={disabled}
        onChange={(e) => {
          const f = e.target.files?.[0];
          if (f) onChoose(f);
        }}
        style={{ display: 'none' }}
      />
      <FiUpload size={11} />
      {hasExisting ? 'Replace signature' : 'Choose signature'}
    </label>
  );
}

// ═══════════════════════════════════════════════════════════════════════
// Style helpers
// ═══════════════════════════════════════════════════════════════════════

function Label({
  children,
  inline,
}: {
  children: React.ReactNode;
  inline?: boolean;
}) {
  return (
    <div
      style={{
        fontSize: 10,
        fontWeight: 700,
        color: '#64748b',
        textTransform: 'uppercase',
        letterSpacing: '0.08em',
        marginBottom: inline ? 0 : 5,
      }}
    >
      {children}
    </div>
  );
}

function inputStyle(): React.CSSProperties {
  return {
    width: '100%',
    background: '#fff',
    border: '1px solid #e2e8f0',
    borderRadius: 7,
    padding: '8px 11px',
    fontSize: 13,
    fontWeight: 500,
    color: '#0b1220',
    height: 36,
    outline: 'none',
    fontFamily: 'inherit',
    boxSizing: 'border-box',
  };
}

function btnPrimary(disabled = false): React.CSSProperties {
  return {
    background: disabled ? '#cbd5e1' : '#15803d',
    color: '#fff',
    border: 'none',
    padding: '8px 16px',
    borderRadius: 7,
    fontSize: 12,
    fontWeight: 700,
    cursor: disabled ? 'not-allowed' : 'pointer',
    display: 'inline-flex',
    alignItems: 'center',
    gap: 5,
    letterSpacing: '0.02em',
  };
}

function btnSecondary(disabled = false): React.CSSProperties {
  return {
    background: '#fff',
    color: '#475569',
    border: '1px solid #e2e8f0',
    padding: '8px 13px',
    borderRadius: 7,
    fontSize: 11,
    fontWeight: 500,
    cursor: disabled ? 'not-allowed' : 'pointer',
    display: 'inline-flex',
    alignItems: 'center',
    gap: 5,
    opacity: disabled ? 0.6 : 1,
  };
}

function formatDate(d?: string | Date | null): string {
  if (!d) return '—';
  const dt = typeof d === 'string' ? new Date(d) : d;
  if (isNaN(dt.getTime())) return '—';
  return dt.toLocaleDateString('en-GB', {
    day: '2-digit',
    month: 'short',
    year: 'numeric',
  });
}

function todayDateString(): string {
  const d = new Date();
  const y = d.getFullYear();
  const m = String(d.getMonth() + 1).padStart(2, '0');
  const day = String(d.getDate()).padStart(2, '0');
  return `${y}-${m}-${day}`;
}