/**
 * ComparisonView — the parent-first compare screen: a sticky school bar and
 * six sections (At a glance / Ofsted / Academics / Getting a place / Who
 * goes there / Explore trends), every number anchored against the England
 * average or the computed state-school benchmark with provenance-correct
 * labels. Layout and copy follow the reviewed mockups
 * (docs/superpowers/specs/mockups/).
 */

'use client';

import { useEffect, useRef, useState, type CSSProperties } from 'react';
import { useRouter, usePathname, useSearchParams } from 'next/navigation';
import { useComparison } from '@/hooks/useComparison';

import { SchoolSearchModal } from './SchoolSearchModal';
import { EmptyState } from './EmptyState';
import { CompareAtAGlance } from './compare/CompareAtAGlance';
import { CompareOfsted } from './compare/CompareOfsted';
import { CompareAcademics } from './compare/CompareAcademics';
import { CompareAdmissions } from './compare/CompareAdmissions';
import { CompareCommunity } from './compare/CompareCommunity';
import { TrendsExplorer, PRIMARY_CATEGORIES, SECONDARY_CATEGORIES } from './compare/TrendsExplorer';
import type {
  Benchmarks,
  ComparisonData,
  MetricDefinition,
  NationalAverages,
  School,
} from '@/lib/types';
import { CHART_COLORS, schoolUrl, shortName } from '@/lib/utils';
import { fetchComparison } from '@/lib/api';
import { track } from '@/lib/analytics';
import styles from './ComparisonView.module.css';

interface ComparisonViewProps {
  initialData: Record<string, ComparisonData> | null;
  initialNationalAverages?: NationalAverages;
  initialBenchmarks?: Benchmarks;
  initialUrns: number[];
  metrics: MetricDefinition[];
  selectedMetric: string;
}

export function ComparisonView({
  initialData,
  initialNationalAverages,
  initialBenchmarks,
  initialUrns,
  metrics,
  selectedMetric: initialMetric,
}: ComparisonViewProps) {
  const router = useRouter();
  const pathname = usePathname();
  const searchParams = useSearchParams();
  const { selectedSchools, removeSchool, replaceSchools, isInitialized } = useComparison();

  const [selectedMetric, setSelectedMetric] = useState(initialMetric);
  const [isModalOpen, setIsModalOpen] = useState(false);
  const [comparisonData, setComparisonData] = useState(initialData);
  const [nationalAverages, setNationalAverages] = useState<NationalAverages | undefined>(
    initialNationalAverages,
  );
  const [benchmarks, setBenchmarks] = useState<Benchmarks | undefined>(initialBenchmarks);
  const [shareConfirm, setShareConfirm] = useState(false);
  const [comparePhase, setComparePhase] = useState<'primary' | 'secondary'>('primary');
  // Tracks whether the user has explicitly clicked a phase tab.
  // While true, auto-phase detection is suppressed so manual selections aren't overridden.
  const phaseLockedByUser = useRef(false);

  // Seed context from the URL on mount. An explicit ?urns=… (e.g. a link a
  // parent shared with their partner) always wins over this visitor's stored
  // selection — otherwise the recipient silently sees their own old schools.
  // The replacement is then persisted like any other selection change.
  useEffect(() => {
    if (!isInitialized) return;
    if (initialUrns.length > 0 && initialData) {
      const urlSchools = initialUrns
        .map((urn) => initialData[String(urn)]?.school_info)
        .filter((info): info is NonNullable<typeof info> => Boolean(info));
      const sameSet =
        urlSchools.length === selectedSchools.length &&
        urlSchools.every((s) => selectedSchools.some((sel) => sel.urn === s.urn));
      if (urlSchools.length > 0 && !sameSet) {
        replaceSchools(urlSchools);
      }
    }
    // Re-seed when a client-side navigation lands on a different ?urns= set
    // (initialUrns/initialData are new props on the same component instance).
  }, [isInitialized, initialUrns.join(',')]); // eslint-disable-line react-hooks/exhaustive-deps

  const urnKey = selectedSchools.map((s) => s.urn).join(',');

  // Sync the URL with the selection + metric. Pure navigation state — no
  // fetching here: metric changes are presentational (the data is already
  // client-side) and must not refire the comparison request.
  useEffect(() => {
    const params = new URLSearchParams(searchParams);

    if (urnKey) {
      params.set('urns', urnKey);
    } else {
      params.delete('urns');
    }

    params.set('metric', selectedMetric);

    const newUrl = `${pathname}?${params.toString()}`;
    router.replace(newUrl, { scroll: false });
  }, [urnKey, selectedMetric, pathname, searchParams, router]);

  // Fetch when the school set changes, but only for schools we don't already
  // have data for. This skips the refetch of SSR-rendered data on load AND
  // avoids a network call when a school is merely removed. A ref holds the
  // latest data so the effect can read it without re-running on every fetch.
  //
  // Correctness note: we must NOT null the data on a transient empty urnKey.
  // On mount the basket is empty for a beat before it hydrates from the URL,
  // and blanking here (then skipping the refetch because SSR "covers" the set)
  // was leaving the page empty on refresh. The render already shows the empty
  // state whenever `selectedSchools` is empty, so stale data for deselected
  // schools is harmless — it's simply unused.
  const comparisonDataRef = useRef(comparisonData);
  comparisonDataRef.current = comparisonData;

  useEffect(() => {
    if (!isInitialized || !urnKey) return;

    const have = comparisonDataRef.current ?? {};
    const covered = urnKey.split(',').every((urn) => have[urn] != null);
    if (covered) return;

    // Guard against out-of-order responses: while the basket hydrates from
    // localStorage it can transiently hold a DIFFERENT school set than the
    // URL, firing a fetch for schools the user is no longer comparing. That
    // stale response must not replace data for the current set — it blanked
    // every section until a hard refresh. Cleanup marks the run cancelled
    // when urnKey moves on, so only the current selection's response is
    // applied (replacing the map keeps it bounded and guarantees a re-added
    // school is refetched fresh rather than served a lingering old entry).
    let cancelled = false;
    fetchComparison(urnKey, { cache: 'no-store' })
      .then((data) => {
        if (cancelled) return;
        setComparisonData(data.comparison);
        setNationalAverages(data.national_averages);
        setBenchmarks(data.benchmarks);
      })
      .catch((err) => {
        // Keep whatever we already have (SSR data or a previous fetch) rather
        // than blanking the page — a transient refetch failure shouldn't
        // destroy a working comparison the user is looking at.
        console.error('Failed to fetch comparison:', err);
      });
    return () => {
      cancelled = true;
    };
  }, [urnKey, isInitialized]);

  const primarySchools = selectedSchools.filter((school) => {
    const info = comparisonData?.[school.urn]?.school_info;
    const hasPrimaryData =
      info?.rwm_expected_pct != null ||
      comparisonData?.[school.urn]?.yearly_data?.some((d) => d.rwm_expected_pct != null);
    if (hasPrimaryData) return true;
    return school.phase?.toLowerCase().includes('primary') || false;
  });

  const secondarySchools = selectedSchools.filter((school) => {
    const info = comparisonData?.[school.urn]?.school_info;
    const hasSecondaryData =
      info?.attainment_8_score != null ||
      comparisonData?.[school.urn]?.yearly_data?.some((d) => d.attainment_8_score != null);
    if (hasSecondaryData) return true;
    return school.phase?.toLowerCase().includes('secondary') || false;
  });

  // Auto-select tab with more schools and sync the metric to match the phase.
  useEffect(() => {
    if (!comparisonData || selectedSchools.length === 0) return;
    if (phaseLockedByUser.current) return;
    const newPhase = secondarySchools.length > primarySchools.length ? 'secondary' : 'primary';
    setComparePhase(newPhase);
    const phaseCategories = newPhase === 'secondary' ? SECONDARY_CATEGORIES : PRIMARY_CATEGORIES;
    const metricFitsPhase = metrics.some(
      (m) => m.key === selectedMetric && phaseCategories.includes(m.category),
    );
    if (!metricFitsPhase) {
      setSelectedMetric(newPhase === 'secondary' ? 'attainment_8_score' : 'rwm_expected_pct');
    }
    // selectedSchools is a dep because the basket hydrates after mount: the
    // first run sees an empty basket and bails, so it must re-fire when the
    // schools arrive. primarySchools/secondarySchools/metrics/selectedMetric
    // are intentionally omitted (derived or would cause loops).
  }, [comparisonData, selectedSchools]); // eslint-disable-line react-hooks/exhaustive-deps

  const handlePhaseChange = (phase: 'primary' | 'secondary') => {
    phaseLockedByUser.current = true;
    setComparePhase(phase);
    setSelectedMetric(phase === 'secondary' ? 'attainment_8_score' : 'rwm_expected_pct');
  };

  // compare_viewed: fire once after the page has its first selection.
  const compareViewedRef = useRef(false);
  useEffect(() => {
    if (compareViewedRef.current) return;
    if (selectedSchools.length === 0) return;
    compareViewedRef.current = true;
    const primaryCount = selectedSchools.filter((s) =>
      s.phase?.toLowerCase().includes('primary'),
    ).length;
    const secondaryCount = selectedSchools.length - primaryCount;
    const phaseMix =
      primaryCount === 0 ? 'all_secondary' : secondaryCount === 0 ? 'all_primary' : 'mixed';
    track('compare_viewed', { school_count: selectedSchools.length, phase_mix: phaseMix });
  }, [selectedSchools]);

  const handleRemoveSchool = (urn: number) => {
    removeSchool(urn);
    track('compare_school_removed', { urn, from: 'compare' });
  };

  const handleShare = async () => {
    const url = window.location.href;
    const count = selectedSchools.length;
    const shareData = {
      title: 'School comparison · schoolcompare',
      text:
        count > 0
          ? `Comparing ${count} school${count === 1 ? '' : 's'} on schoolcompare`
          : 'schoolcompare',
      url,
    };
    if (
      typeof navigator !== 'undefined' &&
      navigator.share &&
      (!navigator.canShare || navigator.canShare(shareData))
    ) {
      try {
        await navigator.share(shareData);
        track('compare_shared', { method: 'native', school_count: count });
        return;
      } catch (err) {
        if ((err as DOMException)?.name === 'AbortError') return;
      }
    }
    try {
      await navigator.clipboard.writeText(url);
      track('compare_shared', { method: 'clipboard', school_count: count });
      setShareConfirm(true);
      setTimeout(() => setShareConfirm(false), 2000);
    } catch {
      /* fallback: do nothing */
    }
  };

  const isPrimary = comparePhase === 'primary';
  const activeSchools = isPrimary ? primarySchools : secondarySchools;

  if (selectedSchools.length === 0) {
    return (
      <div className={styles.container}>
        <header className={styles.header}>
          <h1>Compare Schools</h1>
          <p className={styles.subtitle}>
            Add schools to your comparison basket to see them side by side — inspection results,
            academics, admissions and community.
          </p>
        </header>

        <EmptyState
          title="No schools selected"
          message="Add schools from the home page or search to start comparing."
          action={{
            label: '+ Add Schools to Compare',
            onClick: () => setIsModalOpen(true),
          }}
        />

        <SchoolSearchModal isOpen={isModalOpen} onClose={() => setIsModalOpen(false)} />
      </div>
    );
  }

  // Build filtered comparison data for the active phase
  const activeComparisonData: Record<string, ComparisonData> = {};
  if (comparisonData) {
    activeSchools.forEach((s) => {
      if (comparisonData[s.urn]) {
        activeComparisonData[s.urn] = comparisonData[s.urn];
      }
    });
  }
  const hasData = Object.keys(activeComparisonData).length > 0;

  return (
    <div className={styles.container}>
      <header className={styles.header}>
        <div className={styles.headerContent}>
          <div>
            <h1>Compare Schools</h1>
            <p className={styles.subtitle}>
              {selectedSchools.length} school{selectedSchools.length !== 1 ? 's' : ''} side by side
              — each number anchored against the England average so you can tell at a glance
              what&apos;s typical and what stands out.
            </p>
          </div>
          <div className={styles.headerActions}>
            <button onClick={() => setIsModalOpen(true)} className="btn btn-primary">
              + Add School
            </button>
            <button onClick={handleShare} className="btn btn-tertiary" title="Copy comparison link">
              <svg
                viewBox="0 0 24 24"
                fill="none"
                stroke="currentColor"
                strokeWidth="2"
                width="16"
                height="16"
              >
                <path d="M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8" />
                <polyline points="16 6 12 2 8 6" />
                <line x1="12" y1="2" x2="12" y2="15" />
              </svg>
              {shareConfirm ? 'Copied!' : 'Share'}
            </button>
          </div>
        </div>
      </header>

      {/* Phase Tabs */}
      {secondarySchools.length > 0 && primarySchools.length > 0 && (
        <div className={styles.phaseTabs}>
          <button
            className={`${styles.phaseTab} ${isPrimary ? styles.phaseTabActive : ''}`}
            onClick={() => handlePhaseChange('primary')}
          >
            Primary ({primarySchools.length})
          </button>
          <button
            className={`${styles.phaseTab} ${!isPrimary ? styles.phaseTabActive : ''}`}
            onClick={() => handlePhaseChange('secondary')}
          >
            Secondary ({secondarySchools.length})
          </button>
        </div>
      )}

      {activeSchools.length === 0 ? (
        <EmptyState
          title={`No ${comparePhase} schools in your comparison`}
          message={`Add ${comparePhase} schools from search results to compare them here.`}
          action={{
            label: '+ Add Schools',
            onClick: () => setIsModalOpen(true),
          }}
        />
      ) : (
        <>
          {/* Sticky school bar — column identity while scrolling. On desktop
              it shares the sections' grid template (via --school-count) so
              each chip sits exactly over the column it labels. */}
          <div
            className={styles.schoolBar}
            style={{ '--school-count': activeSchools.length } as CSSProperties}
            aria-label="Schools in this comparison"
          >
            {/* Fills the 200px label rail on desktop (hidden on mobile).
                All-through schools must not be miscounted as "primary
                schools"/"secondary schools" — mixed baskets get "· primary
                view" phrasing instead. */}
            <div className={styles.barCaption}>
              <span className={styles.barCaptionEyebrow}>Comparing</span>
              <span className={styles.barCaptionCount}>
                {activeSchools.every((sch) =>
                  sch.phase?.toLowerCase().includes(comparePhase),
                )
                  ? `${activeSchools.length} ${comparePhase} school${activeSchools.length === 1 ? '' : 's'}`
                  : `${activeSchools.length} schools · ${comparePhase} view`}
              </span>
            </div>
            {activeSchools.map((school, index) => (
              <div
                key={school.urn}
                className={styles.schoolChip}
                style={{ borderTopColor: CHART_COLORS[index % CHART_COLORS.length] }}
              >
                <span
                  className={styles.chipDot}
                  style={{ background: CHART_COLORS[index % CHART_COLORS.length] }}
                  aria-hidden="true"
                />
                <span className={styles.chipText}>
                  <a className={styles.chipName} href={schoolUrl(school.urn, school.school_name)}>
                    <span className={styles.chipNameFull}>{school.school_name}</span>
                    <span className={styles.chipNameShort}>{shortName(school.school_name)}</span>
                  </a>
                  <span className={styles.chipMeta}>
                    {[
                      /all.?through/i.test(school.phase ?? '') ? 'All-through' : null,
                      school.local_authority,
                      school.school_type,
                    ]
                      .filter(Boolean)
                      .join(' · ')}
                  </span>
                </span>
                <button
                  onClick={() => handleRemoveSchool(school.urn)}
                  className={styles.chipRemove}
                  aria-label={`Remove ${school.school_name}`}
                  title="Remove from comparison"
                >
                  ×
                </button>
              </div>
            ))}
          </div>

          {hasData && (
            <>
              <CompareAtAGlance
                schools={activeSchools}
                data={activeComparisonData}
                nationalAverages={nationalAverages}
                benchmarks={benchmarks}
                isSecondary={!isPrimary}
              />
              <CompareOfsted schools={activeSchools} data={activeComparisonData} />
              <CompareAcademics
                schools={activeSchools}
                data={activeComparisonData}
                nationalAverages={nationalAverages}
                benchmarks={benchmarks}
                isSecondary={!isPrimary}
              />
              <CompareAdmissions
                schools={activeSchools}
                data={activeComparisonData}
                isSecondary={!isPrimary}
              />
              <CompareCommunity
                schools={activeSchools}
                data={activeComparisonData}
                benchmarks={benchmarks}
                isSecondary={!isPrimary}
              />
              <TrendsExplorer
                schools={activeSchools}
                data={activeComparisonData}
                metrics={metrics}
                metric={selectedMetric}
                onMetricChange={setSelectedMetric}
                isPrimaryPhase={isPrimary}
                nationalAverages={nationalAverages}
              />

              <p className={styles.footnote}>
                Sources: DfE Compare School Performance (KS2/KS4 results), Ofsted inspection
                outcomes, DfE school admissions data, school census. England averages for test
                results are official DfE figures; other benchmarks are state-school averages
                computed from our dataset. Following DfE practice, figures based on 5 or fewer
                pupils are suppressed and shown as &quot;no data&quot;.
              </p>
            </>
          )}
        </>
      )}

      <SchoolSearchModal isOpen={isModalOpen} onClose={() => setIsModalOpen(false)} />
    </div>
  );
}
