/**
 * Student Tests — PR 3 §6.2
 *
 * Read-only mirror of the teacher Tests hub for the student side. Lists
 * published tests, lets the student submit / resubmit, and surfaces marked
 * scripts once the teacher has returned the work. Adds two test-specific
 * fields over the homework view: test_date and duration_minutes.
 */

import { useEffect, useMemo, useState } from 'react';
import { createPortal } from 'react-dom';
import { 
  BookOpen, Calendar, ChevronRight, Search, X, Download,
  CheckCircle2, Clock, Send, FileText, Award, Inbox,
  AlertCircle, Loader2, Eye, Sparkles, Hourglass
} from 'lucide-react';
import { useAuthStore } from '../../store/auth';
import { useTestStore, type TestPaper, type TestSubmission } from '../../store/tests';
import { useAttachmentStore } from '../../store/attachments';
import { AttachmentList } from '../../components/AttachmentList';

type StatusFilter = 'open' | 'submitted' | 'graded' | 'returned';

interface TestDetailProps {
  test: TestPaper;
  submission: TestSubmission | null;
  onClose: () => void;
  onSubmitted: () => void;
}

function TestDetail({ test, submission, onClose, onSubmitted }: TestDetailProps) {
  const [submitContent, setSubmitContent] = useState(submission?.content || '');
  const [submitFile, setSubmitFile] = useState<File | null>(null);
  const [submitting, setSubmitting] = useState(false);
  const [submitError, setSubmitError] = useState<string | null>(null);
  const [previewAtt, setPreviewAtt] = useState<{ uid: string; name: string; mime: string } | null>(null);
  const [previewUrl, setPreviewUrl] = useState<string | null>(null);
  const [previewLoading, setPreviewLoading] = useState(false);

  const { submit } = useTestStore();
  const { preview, downloadUrl } = useAttachmentStore();

  const testPast = useMemo(() => {
    if (!test.test_date) return false;
    return new Date(test.test_date) < new Date();
  }, [test.test_date]);

  const allowLate = !!test.allow_late_submission;
  const canSubmit = !submission && (!testPast || allowLate);
  const isReturned = submission?.status === 'returned';
  const hasMarkedScripts = (submission?.marked_scripts?.length ?? 0) > 0;

  useEffect(() => {
    if (!previewAtt) {
      if (previewUrl) URL.revokeObjectURL(previewUrl);
      setPreviewUrl(null);
      return;
    }
    let cancelled = false;
    setPreviewLoading(true);
    preview(previewAtt.uid)
      .then(res => { if (!cancelled) setPreviewUrl(res.url); })
      .catch(() => { if (!cancelled) setPreviewUrl(null); })
      .finally(() => { if (!cancelled) setPreviewLoading(false); });
    return () => { cancelled = true; };
  }, [previewAtt, preview, previewUrl]);

  const handleSubmit = async () => {
    if (!submitContent.trim() && !submitFile) {
      setSubmitError('Add a written response or attach a file before submitting.');
      return;
    }
    setSubmitting(true);
    setSubmitError(null);
    try {
      await submit(test.id, {
        content: submitContent,
        file: submitFile || undefined,
      });
      onSubmitted();
    } catch (err: any) {
      setSubmitError(err?.response?.data?.error || err?.message || 'Submission failed');
    } finally {
      setSubmitting(false);
    }
  };

  return createPortal(
    <div className="fixed inset-0 bg-[#002147]/80 backdrop-blur-md z-[150] flex items-center justify-center p-4" onClick={onClose}>
      <div className="bg-card rounded-3xl w-full max-w-4xl shadow-2xl overflow-hidden border border-border max-h-[90vh] flex flex-col" onClick={(e) => e.stopPropagation()}>
        <div className="p-8 border-b border-border flex items-start justify-between gap-4 bg-muted/50 shrink-0 relative overflow-hidden">
          <div className="absolute right-[-20px] top-[-20px] opacity-[0.04] rotate-12">
            <Sparkles size={160} />
          </div>
          <div className="relative z-10 min-w-0">
            <p className="text-[0.65rem] font-black uppercase tracking-[3px] text-primary">{test.subject_name} • Test</p>
            <h2 className="text-2xl font-black text-text tracking-tight mt-1 truncate">{test.title}</h2>
            <div className="flex flex-wrap items-center gap-4 mt-2">
              {test.test_date && (
                <p className="text-[0.7rem] font-bold text-text-muted uppercase tracking-widest">
                  <Calendar size={12} className="inline mr-1" />
                  Test Date: {new Date(test.test_date).toLocaleDateString()}
                  {testPast && <span className="ml-2 text-rose-600">(Past)</span>}
                </p>
              )}
              {test.duration_minutes && (
                <p className="text-[0.7rem] font-bold text-text-muted uppercase tracking-widest">
                  <Hourglass size={12} className="inline mr-1" />
                  Duration: {test.duration_minutes} min
                </p>
              )}
            </div>
          </div>
          <button
            type="button"
            onClick={onClose}
            className="relative z-10 p-2 rounded-xl bg-card border border-border text-text-muted hover:text-rose-500 hover:bg-rose-50 transition-colors"
            aria-label="Close detail"
          >
            <X size={20} />
          </button>
        </div>

        <div className="flex-1 overflow-y-auto p-8 space-y-8 custom-scrollbar">
          {test.instructions && (
            <section className="space-y-2">
              <h4 className="text-[0.65rem] font-black uppercase tracking-[3px] text-text-muted px-1">Instructions</h4>
              <div className="p-5 bg-blue-50/10 border border-blue-100/30 rounded-2xl">
                <p className="text-sm text-text-secondary font-medium leading-relaxed whitespace-pre-wrap">{test.instructions}</p>
              </div>
            </section>
          )}

          {test.description && (
            <section className="space-y-2">
              <h4 className="text-[0.65rem] font-black uppercase tracking-[3px] text-text-muted px-1">Description</h4>
              <p className="text-sm text-text-muted font-medium leading-relaxed whitespace-pre-wrap">{test.description}</p>
            </section>
          )}

          <section className="space-y-2">
            <h4 className="text-[0.65rem] font-black uppercase tracking-[3px] text-text-muted px-1">Reference Materials</h4>
            <AttachmentList
              parent_kind="test"
              parent_id={test.id}
              emptyMessage="No reference materials attached."
            />
          </section>

          {submission && (
            <section className="space-y-3">
              <h4 className="text-[0.65rem] font-black uppercase tracking-[3px] text-text-muted px-1">My Submission</h4>
              <div className="bg-card border border-border rounded-2xl p-5 space-y-4">
                <div className="flex flex-wrap items-center gap-3">
                  <span className={`inline-flex items-center gap-1.5 px-3 py-1 rounded-lg text-[0.65rem] font-black uppercase tracking-widest border ${
                    isReturned
                      ? 'bg-emerald-50 text-emerald-600 border-emerald-100'
                      : submission.status === 'graded'
                        ? 'bg-purple-50 text-purple-600 border-purple-100'
                        : 'bg-blue-50 text-blue-600 border-blue-100'
                  }`}>
                    <CheckCircle2 size={12} />
                    {submission.status || 'submitted'}
                  </span>
                  {submission.submitted_at && (
                    <span className="text-[0.7rem] font-bold text-text-muted uppercase tracking-widest">
                      Submitted {new Date(submission.submitted_at).toLocaleDateString()}
                    </span>
                  )}
                  {submission.grade !== null && submission.grade !== undefined && (
                    <span className="inline-flex items-center gap-1 text-[0.7rem] font-black text-purple-600 uppercase tracking-widest">
                      <Award size={12} /> {submission.grade} / {test.max_score || 100}
                    </span>
                  )}
                </div>

                {submission.content && (
                  <div className="p-4 bg-muted/30 rounded-xl text-sm text-text-secondary leading-relaxed whitespace-pre-wrap">
                    {submission.content}
                  </div>
                )}

                {submission.feedback && (
                  <div className="p-4 bg-purple-50/30 border border-purple-100 rounded-xl">
                    <p className="text-[0.6rem] font-black uppercase tracking-widest text-purple-600 mb-1">Teacher Feedback</p>
                    <p className="text-sm text-text-secondary leading-relaxed whitespace-pre-wrap">{submission.feedback}</p>
                  </div>
                )}

                {(submission.attachments?.length ?? 0) > 0 && (
                  <AttachmentList
                    parent_kind="submission"
                    parent_id={submission.id!}
                    emptyMessage=""
                  />
                )}
              </div>
            </section>
          )}

          {isReturned && hasMarkedScripts && (
            <section className="space-y-3">
              <h4 className="text-[0.65rem] font-black uppercase tracking-[3px] text-text-muted px-1">Marked Scripts</h4>
              <div className="space-y-2">
                {submission!.marked_scripts!.map(att => (
                  <div key={att.uid} className="flex items-center gap-3 p-4 bg-emerald-50/30 border border-emerald-100 rounded-2xl">
                    <div className="w-10 h-10 rounded-xl bg-emerald-50 border border-emerald-100 flex items-center justify-center text-emerald-600">
                      <FileText size={18} />
                    </div>
                    <div className="flex-1 min-w-0">
                      <p className="text-sm font-bold text-text truncate">{att.original_filename}</p>
                      <p className="text-[0.65rem] text-text-muted uppercase tracking-widest font-bold">
                        {(att.size_bytes / 1024).toFixed(1)} KB · Returned {new Date(att.uploaded_at).toLocaleDateString()}
                      </p>
                    </div>
                    <button
                      type="button"
                      onClick={() => setPreviewAtt({ uid: att.uid, name: att.original_filename, mime: att.mime_type })}
                      className="p-2 rounded-xl text-text-muted hover:text-primary hover:bg-blue-50 transition-colors"
                      aria-label={`Preview ${att.original_filename}`}
                    >
                      <Eye size={16} />
                    </button>
                    <a
                      href={downloadUrl(att.stored_filename)}
                      download={att.original_filename}
                      className="p-2 rounded-xl text-text-muted hover:text-primary hover:bg-blue-50 transition-colors"
                      aria-label={`Download ${att.original_filename}`}
                    >
                      <Download size={16} />
                    </a>
                  </div>
                ))}
              </div>
            </section>
          )}

          {canSubmit && (
            <section className="space-y-3">
              <h4 className="text-[0.65rem] font-black uppercase tracking-[3px] text-text-muted px-1">Your Response</h4>
              <textarea
                value={submitContent}
                onChange={(e) => setSubmitContent(e.target.value)}
                placeholder="Write your response here…"
                className="w-full h-40 p-5 bg-muted/30 border border-border rounded-2xl resize-none focus:ring-4 focus:ring-primary/5 focus:bg-card focus:border-primary transition-all text-sm font-medium placeholder:text-text-muted/40"
              />
              <div className="flex items-center justify-between gap-3 flex-wrap">
                <label className="inline-flex items-center gap-2 px-4 py-2 bg-card border border-border rounded-xl text-xs font-bold uppercase tracking-widest text-text-muted hover:text-text hover:bg-muted cursor-pointer transition-colors">
                  <input
                    type="file"
                    className="hidden"
                    onChange={(e) => setSubmitFile(e.target.files?.[0] || null)}
                  />
                  <FileText size={14} />
                  {submitFile ? submitFile.name : 'Attach file'}
                </label>
                {submitFile && (
                  <button
                    type="button"
                    onClick={() => setSubmitFile(null)}
                    className="text-xs font-bold text-rose-600 hover:underline"
                  >
                    Remove file
                  </button>
                )}
              </div>
              {submitError && (
                <div className="flex items-start gap-2 p-3 rounded-xl bg-rose-50 border border-rose-200 text-sm text-rose-700">
                  <AlertCircle size={16} className="mt-0.5 shrink-0" />
                  <span className="flex-1">{submitError}</span>
                </div>
              )}
            </section>
          )}
        </div>

        <div className="p-6 border-t border-border flex justify-end gap-3 shrink-0 bg-muted/50">
          <button
            type="button"
            onClick={onClose}
            className="px-6 py-3 bg-card border border-border text-text-muted rounded-2xl font-black text-xs uppercase tracking-widest hover:bg-muted transition-all"
          >
            Close
          </button>
          {canSubmit && (
            <button
              type="button"
              onClick={handleSubmit}
              disabled={submitting}
              className="flex items-center gap-2 px-6 py-3 bg-primary text-white rounded-2xl font-black text-xs uppercase tracking-widest hover:bg-primary-dark transition-all shadow-lg active:scale-95 disabled:opacity-50 disabled:grayscale"
            >
              {submitting ? <Loader2 size={14} className="animate-spin" /> : <Send size={14} />}
              {submitting ? 'Submitting…' : 'Submit Test'}
            </button>
          )}
        </div>

        {previewAtt && createPortal(
          <div className="fixed inset-0 bg-[#002147]/80 backdrop-blur-md z-[200] flex items-center justify-center p-4" onClick={() => setPreviewAtt(null)}>
            <div
              className="bg-card rounded-3xl shadow-2xl max-w-4xl w-full max-h-[90vh] overflow-hidden border border-border flex flex-col"
              onClick={(e) => e.stopPropagation()}
            >
              <div className="p-5 border-b border-border flex items-center justify-between bg-muted/50">
                <h3 className="text-base font-bold text-text truncate">{previewAtt.name}</h3>
                <button
                  type="button"
                  onClick={() => setPreviewAtt(null)}
                  className="p-2 rounded-xl text-text-muted hover:text-rose-500 hover:bg-rose-50"
                  aria-label="Close preview"
                >
                  <X size={18} />
                </button>
              </div>
              <div className="flex-1 overflow-auto bg-[#002147]/5 p-4 flex items-center justify-center min-h-[300px]">
                {previewLoading ? (
                  <Loader2 size={32} className="animate-spin text-primary" />
                ) : previewUrl ? (
                  previewAtt.mime.startsWith('image/') ? (
                    <img src={previewUrl} alt={previewAtt.name} className="max-w-full max-h-[70vh] object-contain rounded-2xl shadow-lg" />
                  ) : (
                    <iframe src={previewUrl} title={previewAtt.name} className="w-full h-[70vh] bg-card rounded-2xl border border-border" />
                  )
                ) : (
                  <p className="text-sm text-rose-600 font-bold">Could not load preview.</p>
                )}
              </div>
            </div>
          </div>
        ,
          document.body
        )}
      </div>
    </div>
  ,
    document.body
  );
}

export default function StudentTests() {
  const user = useAuthStore(s => s.user);
  const { items, submissions, loading, error, list, mySubmissions } = useTestStore();

  const [activeTab, setActiveTab] = useState<StatusFilter>('open');
  const [search, setSearch] = useState('');
  const [openTest, setOpenTest] = useState<TestPaper | null>(null);
  const [myRows, setMyRows] = useState<TestSubmission[]>([]);

  const loadAll = async () => {
    try {
      await Promise.all([list(), mySubmissions()]);
    } catch (e) {
      console.error(e);
    }
  };

  useEffect(() => {
    loadAll();
    const unsub = useTestStore.subscribe((state) => {
      const merged: TestSubmission[] = [];
      const seen = new Set<number>();
      Object.values(state.submissions).forEach((rows) => {
        (rows as TestSubmission[]).forEach((r) => {
          if (!seen.has(r.id ?? -1)) {
            seen.add(r.id ?? -1);
            merged.push(r);
          }
        });
      });
      setMyRows(merged);
    });
    return () => unsub();
  }, [list, mySubmissions]);

  const submissionFor = (testId: number): TestSubmission | null => {
    const fromMap = submissions[testId]?.find(s => s.student_id === user?.id);
    if (fromMap) return fromMap;
    const fromList = myRows.find(s => s.test_id === testId);
    return fromList || null;
  };

  const filterByTab = (t: TestPaper): boolean => {
    const sub = submissionFor(t.id);
    if (activeTab === 'open') return !sub;
    if (activeTab === 'submitted') return !!sub && sub.status !== 'graded' && sub.status !== 'returned';
    if (activeTab === 'graded') return !!sub && sub.status === 'graded';
    if (activeTab === 'returned') return !!sub && sub.status === 'returned';
    return true;
  };

  const filtered = items
    .filter(filterByTab)
    .filter(t => !search || t.title.toLowerCase().includes(search.toLowerCase()) || t.subject_name?.toLowerCase().includes(search.toLowerCase()));

  const counts = {
    open: items.filter(t => !submissionFor(t.id)).length,
    submitted: items.filter(t => {
      const s = submissionFor(t.id);
      return !!s && s.status !== 'graded' && s.status !== 'returned';
    }).length,
    graded: items.filter(t => submissionFor(t.id)?.status === 'graded').length,
    returned: items.filter(t => submissionFor(t.id)?.status === 'returned').length,
  };

  return (
    <div className="p-4 sm:p-8 space-y-6 max-w-7xl mx-auto">
      <div className="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4 border-b border-border pb-6">
        <div>
          <h1 className="text-2xl font-black text-text tracking-tight uppercase">Tests</h1>
          <p className="text-xs text-text-muted mt-1 uppercase font-bold tracking-widest">
            In-class test papers, submission status, and marked scripts
          </p>
        </div>
      </div>

      <div className="bg-card border border-border rounded-3xl p-2 flex flex-col lg:flex-row items-stretch lg:items-center gap-3">
        <div className="flex p-1 bg-muted/40 rounded-2xl flex-1 overflow-x-auto">
          {([
            { id: 'open', label: 'Open' },
            { id: 'submitted', label: 'Submitted' },
            { id: 'graded', label: 'Graded' },
            { id: 'returned', label: 'Returned' },
          ] as { id: StatusFilter; label: string }[]).map(tab => (
            <button
              key={tab.id}
              onClick={() => setActiveTab(tab.id)}
              className={`flex-1 min-w-[110px] px-4 py-2.5 rounded-xl text-[0.7rem] font-black uppercase tracking-widest transition-all ${
                activeTab === tab.id
                  ? 'bg-card text-primary shadow-sm ring-1 ring-border'
                  : 'text-text-muted hover:text-text'
              }`}
            >
              {tab.label}
              <span className="ml-2 opacity-50">{counts[tab.id]}</span>
            </button>
          ))}
        </div>
        <div className="relative min-w-[260px]">
          <Search size={16} className="absolute left-3 top-1/2 -translate-y-1/2 text-text-muted/40" />
          <input
            type="text"
            value={search}
            onChange={(e) => setSearch(e.target.value)}
            placeholder="Search tests..."
            className="w-full pl-9 pr-4 py-2.5 bg-muted/30 border border-border rounded-xl text-sm font-medium focus:outline-none focus:ring-4 focus:ring-primary/5 focus:bg-card focus:border-primary transition-all"
          />
        </div>
      </div>

      {error && (
        <div className="flex items-start gap-2 p-3 rounded-2xl bg-rose-50 border border-rose-200 text-sm text-rose-700">
          <AlertCircle size={16} className="mt-0.5 shrink-0" />
          <span>{error}</span>
        </div>
      )}

      {loading && items.length === 0 ? (
        <div className="py-20 text-center text-text-muted">
          <Loader2 size={32} className="mx-auto animate-spin text-primary mb-3" />
          <p className="text-xs font-black uppercase tracking-widest">Loading tests…</p>
        </div>
      ) : filtered.length === 0 ? (
        <div className="py-20 text-center bg-card border border-border rounded-3xl">
          <Inbox size={48} className="mx-auto text-text-muted/20 mb-4" />
          <p className="text-xs font-black uppercase tracking-widest text-text-muted">No tests in this view</p>
        </div>
      ) : (
        <div className="grid grid-cols-1 gap-4">
          {filtered.map(t => {
            const sub = submissionFor(t.id);
            return (
              <div
                key={t.id}
                onClick={() => setOpenTest(t)}
                className="bg-card border border-border rounded-3xl p-6 hover:shadow-lg hover:border-primary/30 transition-all cursor-pointer group flex items-center gap-5"
              >
                <div className="w-14 h-14 rounded-2xl bg-primary/10 text-primary border border-primary/20 flex items-center justify-center shrink-0 group-hover:scale-105 transition-transform">
                  <BookOpen size={22} />
                </div>
                <div className="min-w-0 flex-1">
                  <div className="flex items-center gap-2 mb-1 flex-wrap">
                    <span className="text-[0.6rem] font-black uppercase tracking-widest px-2 py-0.5 rounded-md bg-muted text-text-muted">
                      {t.subject_name || 'Subject'}
                    </span>
                    {sub && (
                      <span className={`text-[0.6rem] font-black uppercase tracking-widest px-2 py-0.5 rounded-md ${
                        sub.status === 'returned'
                          ? 'bg-emerald-50 text-emerald-700 border border-emerald-100'
                          : sub.status === 'graded'
                            ? 'bg-purple-50 text-purple-700 border border-purple-100'
                            : 'bg-blue-50 text-blue-700 border border-blue-100'
                      }`}>
                        {sub.status}
                      </span>
                    )}
                  </div>
                  <h3 className="text-lg font-bold text-text group-hover:text-primary transition-colors truncate">{t.title}</h3>
                  <div className="flex items-center gap-4 mt-1.5 text-[0.65rem] font-bold text-text-muted uppercase tracking-widest flex-wrap">
                    {t.test_date && (
                      <span className="flex items-center gap-1">
                        <Calendar size={11} /> Test {new Date(t.test_date).toLocaleDateString()}
                      </span>
                    )}
                    {t.duration_minutes && (
                      <span className="flex items-center gap-1">
                        <Hourglass size={11} /> {t.duration_minutes} min
                      </span>
                    )}
                    {sub?.grade !== null && sub?.grade !== undefined && (
                      <span className="flex items-center gap-1 text-purple-600">
                        <Award size={11} /> {sub.grade}/{t.max_score || 100}
                      </span>
                    )}
                  </div>
                </div>
                <ChevronRight size={20} className="text-text-muted/40 group-hover:text-primary group-hover:translate-x-1 transition-all" />
              </div>
            );
          })}
        </div>
      )}

      {openTest && (
        <TestDetail
          test={openTest}
          submission={submissionFor(openTest.id)}
          onClose={() => setOpenTest(null)}
          onSubmitted={async () => {
            await list();
            await mySubmissions();
          }}
        />
      )}
    </div>
  );
}