'use client';

/**
 * A1 S9 — Slip Reader. Upload/paste a bet-slip screenshot; tesseract OCR
 * (self-hosted, backend) extracts the legs; every field is pre-filled AND
 * editable (needs_review fields amber); confirm grades each leg through
 * the normal engine via POST /api/scan — refusals render honestly; graded
 * legs hand off to the Parlay Lab.
 *
 * DATA SEMANTICS: extracted numbers are USER-SLIP values (what the user's
 * book printed), labeled as such. VYNDR never invents a line or odds — an
 * unreadable field arrives null and stays empty until the user fills it.
 */

import { useCallback, useRef, useState } from 'react';
import SectionHead from '@/components/vyndr/SectionHead';
import VBtn from '@/components/vyndr/VBtn';
import GradeBadge from '@/components/vyndr/GradeBadge';
import { useParlay } from '@/contexts/ParlayContext';
import { currentAccessToken } from '@/lib/authToken';

type Sport = 'MLB' | 'NBA' | 'WNBA';

interface ParsedLeg {
  player: string | null;
  stat: string | null;
  line: number | null;
  side: 'over' | 'under' | null;
  odds: number | null;
  confidence?: Record<string, number>;
  needs_review: boolean;
}

interface EditLeg {
  player: string;
  stat: string;
  line: string;
  side: 'over' | 'under';
  odds: string;
  needs_review: boolean;
  flagged: { player: boolean; stat: boolean; line: boolean; side: boolean; odds: boolean };
}

interface LegGrade {
  status: 'pending' | 'graded' | 'refused' | 'error';
  grade?: string;
  confidence?: number;
  message?: string;
}

const STAT_OPTIONS: Record<Sport, string[]> = {
  MLB: ['hits', 'total_bases', 'home_runs', 'rbi', 'runs', 'stolen_bases', 'doubles', 'walks', 'strikeouts', 'hits_allowed', 'earned_runs', 'innings_pitched'],
  NBA: ['points', 'rebounds', 'assists', 'threes', 'blocks', 'steals', 'pra', 'turnovers'],
  WNBA: ['points', 'rebounds', 'assists', 'threes', 'blocks', 'steals', 'pra', 'turnovers'],
};

const label = (s: string) => s.replace(/_/g, ' ').toUpperCase();

function toEditLeg(l: ParsedLeg): EditLeg {
  return {
    player: l.player ?? '',
    stat: l.stat ?? '',
    line: l.line != null ? String(l.line) : '',
    side: l.side === 'under' ? 'under' : 'over',
    odds: l.odds != null ? (l.odds > 0 ? `+${l.odds}` : String(l.odds)) : '',
    needs_review: l.needs_review,
    flagged: {
      player: l.player == null,
      stat: l.stat == null,
      line: l.line == null,
      side: l.side == null,
      odds: l.odds == null,
    },
  };
}

const inputStyle = (flag: boolean): React.CSSProperties => ({
  width: '100%',
  padding: '8px 10px',
  background: 'var(--bg-2)',
  border: `1px solid ${flag ? 'var(--amber)' : 'var(--border)'}`,
  borderRadius: 6,
  color: flag ? 'var(--amber)' : 'var(--text-0)',
  fontSize: 13,
});

export default function SlipPage() {
  const { addLeg, open } = useParlay();
  const fileRef = useRef<HTMLInputElement>(null);

  const [mode, setMode] = useState<'image' | 'text'>('image');
  const [sport, setSport] = useState<Sport>('MLB');
  const [preview, setPreview] = useState<string | null>(null);
  const [slipText, setSlipText] = useState('');
  const [parsing, setParsing] = useState(false);
  const [error, setError] = useState('');
  const [book, setBook] = useState<string | null>(null);
  const [legs, setLegs] = useState<EditLeg[] | null>(null);
  const [grades, setGrades] = useState<LegGrade[]>([]);
  const [grading, setGrading] = useState(false);
  const [graded, setGraded] = useState(false);
  const [copied, setCopied] = useState(false);
  const [added, setAdded] = useState(false);

  const parse = useCallback(async (payload: { image?: string; text?: string }) => {
    setParsing(true);
    setError('');
    setLegs(null);
    setGrades([]);
    setGraded(false);
    setAdded(false);
    try {
      const token = currentAccessToken();
      const res = await fetch('/api/slips/parse', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          ...(token ? { Authorization: `Bearer ${token}` } : {}),
        },
        body: JSON.stringify(payload),
      });
      const data = await res.json();
      if (!res.ok) {
        setError(data.error || 'The reader could not process that slip.');
        return;
      }
      setBook(data.book ?? null);
      const parsed: ParsedLeg[] = Array.isArray(data.legs) ? data.legs : [];
      if (parsed.length === 0) {
        setError('No legs found on that slip. Try a sharper screenshot or paste the slip text.');
        return;
      }
      setLegs(parsed.map(toEditLeg));
    } catch {
      setError('The reader is offline. Try again shortly.');
    } finally {
      setParsing(false);
    }
  }, []);

  const onFile = useCallback((file: File | null) => {
    if (!file) return;
    if (file.size > 4 * 1024 * 1024) {
      setError('Image too large. 4MB max.');
      return;
    }
    const reader = new FileReader();
    reader.onload = () => {
      const url = String(reader.result || '');
      setPreview(url);
      void parse({ image: url });
    };
    reader.readAsDataURL(file);
  }, [parse]);

  const onPaste = useCallback((e: React.ClipboardEvent) => {
    const item = Array.from(e.clipboardData?.items || []).find((i) => i.type.startsWith('image/'));
    if (item) {
      const f = item.getAsFile();
      if (f) onFile(f);
    }
  }, [onFile]);

  const setField = (i: number, field: keyof EditLeg['flagged'], value: string) => {
    setLegs((prev) => {
      if (!prev) return prev;
      const next = [...prev];
      const leg = { ...next[i], [field]: value } as EditLeg;
      // A user-corrected field is no longer flagged.
      leg.flagged = { ...leg.flagged, [field]: value.trim() === '' };
      next[i] = leg;
      return next;
    });
    setGraded(false);
  };

  const removeLeg = (i: number) => {
    setLegs((prev) => (prev ? prev.filter((_, idx) => idx !== i) : prev));
    setGraded(false);
  };

  const legReady = (l: EditLeg) =>
    l.player.trim() !== '' && l.stat !== '' && l.line.trim() !== '' && Number.isFinite(Number(l.line));

  const gradeAll = async () => {
    if (!legs || grading) return;
    setGrading(true);
    setGrades(legs.map(() => ({ status: 'pending' })));
    const token = currentAccessToken();
    const results: LegGrade[] = [];
    for (const leg of legs) {
      if (!legReady(leg)) {
        results.push({ status: 'error', message: 'Fill player, stat and line first.' });
        continue;
      }
      try {
        const res = await fetch('/api/scan', {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            ...(token ? { Authorization: `Bearer ${token}` } : {}),
          },
          body: JSON.stringify({
            sport,
            player: leg.player.trim(),
            stat: leg.stat,
            line: Number(leg.line),
            direction: leg.side,
            book: 'draftkings',
          }),
        });
        const data = await res.json();
        if (!res.ok) {
          results.push({ status: 'error', message: data.error || 'The engine hit a wall on this leg.' });
        } else if (data.insufficient_data || !data.grade) {
          // Honest refusal — the engine has no model reference for this prop.
          results.push({ status: 'refused', message: 'NO GRADE — insufficient data. The engine does not guess.' });
        } else {
          results.push({ status: 'graded', grade: data.grade, confidence: data.confidence });
        }
      } catch {
        results.push({ status: 'error', message: 'The engine hit a wall on this leg.' });
      }
      setGrades([...results, ...legs.slice(results.length).map(() => ({ status: 'pending' as const }))]);
    }
    setGrades(results);
    setGrading(false);
    setGraded(true);
  };

  const gradedLegs = legs
    ? legs.map((l, i) => ({ leg: l, grade: grades[i] })).filter((x) => x.grade?.status === 'graded')
    : [];

  const addAllToParlay = () => {
    for (const { leg, grade } of gradedLegs) {
      addLeg({
        sport,
        player: leg.player.trim(),
        stat: leg.stat,
        line: Number(leg.line),
        direction: leg.side,
        grade: grade!.grade || '',
        confidence: grade!.confidence ?? 0,
      });
    }
    setAdded(true);
    open();
  };

  const shareText = () => {
    const rows = (legs || []).map((l, i) => {
      const g = grades[i];
      const mark = g?.status === 'graded' ? g.grade : 'NO GRADE';
      return `${l.player} ${l.stat ? label(l.stat) : '?'} ${l.side === 'under' ? 'u' : 'o'}${l.line} · ${mark}`;
    });
    return ['VYNDR read my slip.', ...rows, 'vyndr.app/slip'].join('\n');
  };

  const copyShare = () => {
    if (typeof navigator !== 'undefined' && navigator.clipboard) {
      void navigator.clipboard.writeText(shareText());
      setCopied(true);
      setTimeout(() => setCopied(false), 1800);
    }
  };

  return (
    <section style={{ maxWidth: 720, margin: '0 auto', padding: '28px 16px 96px' }} onPaste={onPaste}>
      <SectionHead accent="var(--g-a)">▚ SLIP READER</SectionHead>
      <h1 className="mono" style={{ fontSize: 28, fontWeight: 800, letterSpacing: '-0.02em', margin: '8px 0 8px' }}>READ MY SLIP</h1>
      <p style={{ fontSize: 14, color: 'var(--text-1)', lineHeight: 1.6, marginBottom: 20 }}>
        Drop a bet-slip screenshot. The reader extracts your legs, you correct anything it was unsure
        about, and the engine grades each one. Free tier reads one slip a day.
      </p>

      {/* Input mode */}
      <div style={{ display: 'flex', gap: 8, marginBottom: 14 }}>
        {(['image', 'text'] as const).map((m) => (
          <button
            key={m}
            className="mono"
            onClick={() => setMode(m)}
            style={{
              padding: '7px 14px', borderRadius: 6, fontSize: 12, fontWeight: 700, cursor: 'pointer',
              background: mode === m ? 'var(--bg-2)' : 'transparent',
              border: `1px solid ${mode === m ? 'var(--g-a)' : 'var(--border)'}`,
              color: mode === m ? 'var(--g-a)' : 'var(--text-1)',
            }}
          >
            {m === 'image' ? 'SCREENSHOT' : 'PASTE TEXT'}
          </button>
        ))}
        <div style={{ marginLeft: 'auto' }}>
          <select
            className="mono"
            value={sport}
            onChange={(e) => setSport(e.target.value as Sport)}
            style={{ ...inputStyle(false), width: 'auto', fontSize: 12 }}
            aria-label="Sport"
          >
            <option value="MLB">MLB</option>
            <option value="NBA">NBA</option>
            <option value="WNBA">WNBA</option>
          </select>
        </div>
      </div>

      {mode === 'image' ? (
        <div
          onClick={() => fileRef.current?.click()}
          style={{
            border: '1px dashed var(--border)', borderRadius: 8, padding: 28, textAlign: 'center',
            cursor: 'pointer', background: 'var(--bg-1)', marginBottom: 16,
          }}
        >
          <input
            ref={fileRef}
            type="file"
            accept="image/*"
            style={{ display: 'none' }}
            onChange={(e) => onFile(e.target.files?.[0] ?? null)}
          />
          {preview ? (
            // eslint-disable-next-line @next/next/no-img-element
            <img src={preview} alt="Slip preview" style={{ maxWidth: '100%', maxHeight: 260, borderRadius: 6 }} />
          ) : (
            <div className="mono" style={{ fontSize: 13, color: 'var(--text-1)' }}>
              CLICK TO UPLOAD · OR PASTE A SCREENSHOT (CTRL+V)
            </div>
          )}
        </div>
      ) : (
        <div style={{ marginBottom: 16 }}>
          <textarea
            className="mono"
            value={slipText}
            onChange={(e) => setSlipText(e.target.value)}
            placeholder={'Aaron Judge Over 1.5\nTotal Bases\n-115'}
            rows={7}
            style={{ ...inputStyle(false), resize: 'vertical', fontSize: 13 }}
          />
          <div style={{ marginTop: 10 }}>
            <VBtn variant="primary" disabled={parsing || !slipText.trim()} onClick={() => void parse({ text: slipText })}>
              {parsing ? 'READING…' : 'READ SLIP TEXT'}
            </VBtn>
          </div>
        </div>
      )}

      {parsing && mode === 'image' && (
        <div className="mono" style={{ fontSize: 13, color: 'var(--g-a)', marginBottom: 16 }}>READING THE SLIP…</div>
      )}
      {error && (
        <div className="mono" style={{ fontSize: 13, color: 'var(--miss, #ff6b6b)', marginBottom: 16 }}>{error}</div>
      )}

      {/* Parsed legs — manual-correct UI */}
      {legs && (
        <div style={{ marginBottom: 20 }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 6 }}>
            <span className="label">
              EXTRACTED LEGS{book ? ` · ${book.toUpperCase()}` : ''}
            </span>
            <span className="mono" style={{ fontSize: 11, color: 'var(--text-1)' }}>
              USER-SLIP VALUES — your book&apos;s numbers, not ours
            </span>
          </div>
          {legs.some((l) => l.needs_review) && (
            <div className="mono" style={{ fontSize: 12, color: 'var(--amber)', marginBottom: 10 }}>
              Amber fields were unreadable or uncertain. The reader does not guess — check them before grading.
            </div>
          )}

          {legs.map((leg, i) => {
            const g = grades[i];
            return (
              <div
                key={i}
                style={{
                  border: `1px solid ${leg.needs_review && !legReady(leg) ? 'var(--amber)' : 'var(--border)'}`,
                  borderRadius: 8, padding: 12, marginBottom: 10, background: 'var(--bg-1)',
                }}
              >
                <div style={{ display: 'grid', gridTemplateColumns: '2fr 1.6fr 0.9fr 1fr 1fr auto', gap: 8, alignItems: 'center' }}>
                  <input
                    className="mono"
                    value={leg.player}
                    placeholder="Player"
                    onChange={(e) => setField(i, 'player', e.target.value)}
                    style={inputStyle(leg.flagged.player)}
                    aria-label={`Leg ${i + 1} player`}
                  />
                  <select
                    className="mono"
                    value={leg.stat}
                    onChange={(e) => setField(i, 'stat', e.target.value)}
                    style={inputStyle(leg.flagged.stat)}
                    aria-label={`Leg ${i + 1} stat`}
                  >
                    <option value="">STAT…</option>
                    {STAT_OPTIONS[sport].map((s) => (
                      <option key={s} value={s}>{label(s)}</option>
                    ))}
                  </select>
                  <input
                    className="mono"
                    value={leg.line}
                    placeholder="Line"
                    inputMode="decimal"
                    onChange={(e) => setField(i, 'line', e.target.value)}
                    style={inputStyle(leg.flagged.line)}
                    aria-label={`Leg ${i + 1} line`}
                  />
                  <select
                    className="mono"
                    value={leg.side}
                    onChange={(e) => setField(i, 'side', e.target.value)}
                    style={inputStyle(leg.flagged.side)}
                    aria-label={`Leg ${i + 1} side`}
                  >
                    <option value="over">OVER</option>
                    <option value="under">UNDER</option>
                  </select>
                  <input
                    className="mono"
                    value={leg.odds}
                    placeholder="Odds"
                    onChange={(e) => setField(i, 'odds', e.target.value)}
                    style={inputStyle(leg.flagged.odds)}
                    aria-label={`Leg ${i + 1} odds`}
                  />
                  <button
                    className="mono"
                    onClick={() => removeLeg(i)}
                    style={{ background: 'transparent', border: 'none', color: 'var(--text-1)', cursor: 'pointer', fontSize: 15 }}
                    aria-label={`Remove leg ${i + 1}`}
                  >
                    ✕
                  </button>
                </div>

                {g && g.status !== 'pending' && (
                  <div style={{ marginTop: 10, display: 'flex', alignItems: 'center', gap: 10 }}>
                    {g.status === 'graded' ? (
                      <>
                        <GradeBadge grade={g.grade || ''} />
                        {g.confidence != null && (
                          <span className="mono" style={{ fontSize: 12, color: 'var(--text-1)' }}>
                            {Math.round(g.confidence)}% confidence
                          </span>
                        )}
                      </>
                    ) : (
                      <span className="mono" style={{ fontSize: 12, color: g.status === 'refused' ? 'var(--amber)' : 'var(--miss, #ff6b6b)' }}>
                        {g.message}
                      </span>
                    )}
                  </div>
                )}
                {g && g.status === 'pending' && grading && (
                  <div className="mono" style={{ marginTop: 10, fontSize: 12, color: 'var(--text-1)' }}>GRADING…</div>
                )}
              </div>
            );
          })}

          <div style={{ display: 'flex', gap: 10, marginTop: 14, flexWrap: 'wrap' }}>
            <VBtn variant="primary" disabled={grading || legs.length === 0 || !legs.every(legReady)} onClick={() => void gradeAll()}>
              {grading ? 'GRADING…' : 'CONFIRM + GRADE'}
            </VBtn>
            {graded && gradedLegs.length >= 1 && !added && (
              <VBtn variant="outline" onClick={addAllToParlay}>
                + ADD {gradedLegs.length} TO PARLAY LAB
              </VBtn>
            )}
            {added && (
              <span className="mono" style={{ fontSize: 12, color: 'var(--g-a)', alignSelf: 'center' }}>
                ✓ In the Lab
              </span>
            )}
          </div>
          {!legs.every(legReady) && (
            <div className="mono" style={{ fontSize: 11, color: 'var(--text-1)', marginTop: 8 }}>
              Every leg needs a player, stat and line before the engine will grade it.
            </div>
          )}
        </div>
      )}

      {/* Share card — VYNDR read my slip */}
      {graded && legs && (
        <div
          style={{
            border: '1px solid var(--border)', borderRadius: 10, padding: 18,
            background: 'var(--bg-1)', marginTop: 8,
          }}
        >
          <div className="label" style={{ marginBottom: 10 }}>VYNDR READ MY SLIP</div>
          {legs.map((l, i) => {
            const g = grades[i];
            return (
              <div key={i} className="mono" style={{ display: 'flex', justifyContent: 'space-between', fontSize: 13, padding: '6px 0', borderBottom: i < legs.length - 1 ? '1px solid var(--border)' : 'none' }}>
                <span>
                  {l.player || '—'} · {l.stat ? label(l.stat) : '?'} {l.side === 'under' ? 'u' : 'o'}{l.line || '?'}
                  {l.odds ? ` · ${l.odds}` : ''}
                </span>
                <span style={{ fontWeight: 800, color: g?.status === 'graded' ? 'var(--g-a)' : 'var(--amber)' }}>
                  {g?.status === 'graded' ? g.grade : 'NO GRADE'}
                </span>
              </div>
            );
          })}
          <div style={{ display: 'flex', gap: 10, marginTop: 14 }}>
            <VBtn variant={copied ? 'primary' : 'outline'} onClick={copyShare}>
              {copied ? '✓ Copied' : 'Copy share text'}
            </VBtn>
          </div>
          <div className="mono" style={{ fontSize: 10, color: 'var(--text-1)', marginTop: 10 }}>
            Slip values are your book&apos;s numbers. Grades are model output. The Ledger keeps the receipts.
          </div>
        </div>
      )}
    </section>
  );
}
