/**
 * How children do academically — tier-1 dot strips anchored on official
 * England averages, tier-2 "More measures" one tap away, equity row against
 * the computed state-school benchmark. Copy verbatim from the reviewed
 * mockups; teacher-assessed measures are labelled as such.
 */

'use client';

import { latestValues, verdict } from '@/lib/compareLogic';
import { isSpecialSchool } from '@/lib/utils';
import type { Benchmarks, ComparisonData, NationalAverages, School } from '@/lib/types';
import { DotStrip } from '@/components/DotStrip';
import { Cell, Chip, RowLabel, Section, SectionGrid, sectionStyles as s } from './sectionShared';
import styles from './CompareAcademics.module.css';

interface StripSpec {
  label: string;
  metric: string;
  anchorKey?: string;
  tip?: string;
  min?: number;
  max?: number;
  unit?: string;
}

const TIER1_PRIMARY: StripSpec[] = [
  {
    label: 'Reading, writing & maths — expected standard',
    metric: 'rwm_expected_pct',
    anchorKey: 'rwm_expected_pct',
    tip: '% of Year 6 pupils reaching the expected standard in reading, writing and maths.',
  },
  { label: 'Reading', metric: 'reading_expected_pct', anchorKey: 'reading_expected_pct' },
  {
    label: 'Writing (teacher-assessed)',
    metric: 'writing_expected_pct',
    anchorKey: 'writing_expected_pct',
    tip: 'Writing is assessed by teachers, not tested.',
  },
  { label: 'Maths', metric: 'maths_expected_pct', anchorKey: 'maths_expected_pct' },
  {
    label: 'Working at a higher standard than expected',
    metric: 'rwm_high_pct',
    anchorKey: 'rwm_high_pct',
    tip: 'A high score in the reading and maths tests plus “greater depth” in teacher-assessed writing.',
  },
];

const TIER2_PRIMARY: StripSpec[] = [
  {
    label: 'Grammar, punctuation & spelling — expected standard',
    metric: 'gps_expected_pct',
    anchorKey: 'gps_expected_pct',
  },
  {
    label: 'Science — expected standard (teacher-assessed)',
    metric: 'science_expected_pct',
    anchorKey: 'science_expected_pct',
    tip: 'Teacher-assessed, like writing — there has been no KS2 science test since 2009, so comparisons are indicative.',
  },
  {
    label: 'Average scaled score — reading',
    metric: 'reading_avg_score',
    anchorKey: 'reading_avg_score',
    min: 100,
    max: 120,
    unit: '',
  },
  {
    label: 'Average scaled score — maths',
    metric: 'maths_avg_score',
    anchorKey: 'maths_avg_score',
    min: 100,
    max: 120,
    unit: '',
  },
  {
    label: 'Average scaled score — grammar, punctuation & spelling',
    metric: 'gps_avg_score',
    anchorKey: 'gps_avg_score',
    min: 100,
    max: 120,
    unit: '',
  },
];

function Strip({
  spec,
  data,
  urns,
  schoolNames,
  national,
  special,
}: {
  spec: StripSpec;
  data: Record<string, ComparisonData>;
  urns: number[];
  schoolNames: string[];
  national: Record<string, number> | undefined;
  /** Per-school special-school flag; special schools' mainstream attainment is
   * not a fair comparison, so it's dropped from the strip (no dot). */
  special: boolean[];
}) {
  const values = latestValues(data, urns, spec.metric).map((v, i) =>
    v != null && !special[i] ? Math.round(v) : null,
  );
  const anchorValue = spec.anchorKey ? national?.[spec.anchorKey] : undefined;
  const anchor =
    anchorValue != null
      ? { value: anchorValue, label: `England ${Math.round(anchorValue)}${spec.unit ?? '%'}` }
      : null;
  if (values.every((v) => v == null)) return null;
  return (
    <DotStrip
      label={spec.label}
      values={values}
      schoolNames={schoolNames}
      anchor={anchor}
      min={spec.min ?? 0}
      max={spec.max ?? 100}
      unit={spec.unit ?? '%'}
      tip={spec.tip}
    />
  );
}

export function CompareAcademics({
  schools,
  data,
  nationalAverages,
  benchmarks,
  isSecondary: propIsSecondary,
}: {
  schools: School[];
  data: Record<string, ComparisonData>;
  nationalAverages?: NationalAverages;
  benchmarks?: Benchmarks;
  isSecondary?: boolean;
}) {
  const urns = schools.map((school) => school.urn);
  const schoolNames = schools.map((school) => school.school_name);
  // Special schools / PRUs / AP: their pupils sit the same assessments but very
  // few reach the mainstream standard, so their attainment isn't a fair
  // like-for-like comparison — drop it (progress banding, which IS meaningful,
  // is kept).
  const specialFlags = schools.map((school) => isSpecialSchool(school));
  const dropSpecial = (vals: Array<number | null>) =>
    vals.map((v, i) => (specialFlags[i] ? null : v));
  const isSecondary = propIsSecondary !== undefined ? propIsSecondary : schools.some(
    (school) => data[String(school.urn)]?.school_info?.attainment_8_score != null,
  );

  if (isSecondary) {
    const att8 = dropSpecial(latestValues(data, urns, 'attainment_8_score'));
    const banding = urns.map((urn) => {
      const rows = data[String(urn)]?.yearly_data ?? [];
      for (let i = rows.length - 1; i >= 0; i--) {
        if (rows[i].progress_8_banding) return rows[i].progress_8_banding as string;
      }
      return null;
    });
    // DfE stopped publishing Progress 8 from 2024/25: those GCSE year groups
    // sat no KS2 tests (COVID), so there is no baseline to measure progress
    // from. A bare "No data" reads as a gap on our side — say why. Judged
    // PER SCHOOL on its own latest data year: a school whose data simply
    // stops earlier (an unrelated gap) must not borrow the COVID explanation
    // from a neighbour that does have 2024/25 data.
    const p8NotPublished = urns.map((urn) => {
      const rows = data[String(urn)]?.yearly_data ?? [];
      const y = rows.length ? Math.trunc(rows[rows.length - 1].year) : 0;
      return y >= 202425;
    });
    const grade5 = dropSpecial(latestValues(data, urns, 'english_maths_strong_pass_pct'));
    const ebacc = dropSpecial(latestValues(data, urns, 'ebacc_entry_pct'));
    const att8Anchor = nationalAverages?.secondary?.attainment_8_score;
    const grade5Anchor = nationalAverages?.secondary?.english_maths_strong_pass_pct;
    const ebaccAnchor = nationalAverages?.secondary?.ebacc_entry_pct;

    // Every headline number gets its England anchor + verdict chip, so the
    // "anchored against the England average" promise holds for the grade-5
    // and EBacc rows too, not just Attainment 8.
    const anchorChip = (value: number | null, anchor: number | null | undefined, tol: number) => {
      if (value == null || anchor == null) return null;
      const v = verdict(value, anchor, tol);
      return (
        <Chip tone={v === 'above' ? 'good' : v === 'below' ? 'warn' : 'neutral'}>
          {v === 'above' ? 'Above' : v === 'below' ? 'Below' : 'Close to'} England average
        </Chip>
      );
    };

    return (
      <Section
        title="How students do academically"
        how="GCSE results (latest year). Attainment 8 averages performance across eight subjects; Progress 8 shows how much progress students make compared with similar students nationally — the wording is DfE's own banding."
      >
        <SectionGrid schools={schools}>
          <RowLabel tip="Average Attainment 8 score across eight GCSE subjects.">Attainment 8</RowLabel>
          {schools.map((school, i) => (
            <Cell key={school.urn} school={school} index={i}>
              {att8[i] != null ? (
                <>
                  <span className={s.big}>{(att8[i] as number).toFixed(1)}</span>{' '}
                  {anchorChip(att8[i], att8Anchor, 2)}
                  {att8Anchor != null && (
                    <span className={s.small}>England average {att8Anchor.toFixed(1)}</span>
                  )}
                </>
              ) : (
                <span className={s.small}>No data</span>
              )}
            </Cell>
          ))}

          <RowLabel tip="DfE's own plain-English Progress 8 label.">Progress 8</RowLabel>
          {schools.map((school, i) => (
            <Cell key={school.urn} school={school} index={i}>
              {banding[i] ? (
                <Chip
                  tone={
                    /well above|above/i.test(banding[i] as string)
                      ? 'good'
                      : /well below|below/i.test(banding[i] as string)
                        ? 'warn'
                        : 'neutral'
                  }
                >
                  {banding[i]}
                </Chip>
              ) : p8NotPublished[i] ? (
                <span className={s.small}>
                  Not published — this GCSE year group sat no KS2 tests (COVID), so DfE has no
                  baseline to measure progress from
                </span>
              ) : (
                <span className={s.small}>No data</span>
              )}
            </Cell>
          ))}

          <RowLabel tip="% achieving grade 5 or above in both English and maths GCSEs.">
            Grade 5+ in English &amp; maths
          </RowLabel>
          {schools.map((school, i) => (
            <Cell key={school.urn} school={school} index={i}>
              {grade5[i] != null ? (
                <>
                  <span className={s.big} style={{ fontSize: '1.1rem' }}>
                    {Math.round(grade5[i] as number)}%
                  </span>{' '}
                  {anchorChip(grade5[i], grade5Anchor, 3)}
                  {grade5Anchor != null && (
                    <span className={s.small}>England average {Math.round(grade5Anchor)}%</span>
                  )}
                </>
              ) : (
                <span className={s.small}>No data</span>
              )}
            </Cell>
          ))}

          <RowLabel tip="% entering the English Baccalaureate subject combination.">EBacc entry</RowLabel>
          {schools.map((school, i) => (
            <Cell key={school.urn} school={school} index={i}>
              {ebacc[i] != null ? (
                <>
                  <span className={s.big} style={{ fontSize: '1.1rem' }}>
                    {Math.round(ebacc[i] as number)}%
                  </span>{' '}
                  {anchorChip(ebacc[i], ebaccAnchor, 3)}
                  {ebaccAnchor != null && (
                    <span className={s.small}>England average {Math.round(ebaccAnchor)}%</span>
                  )}
                </>
              ) : (
                <span className={s.small}>No data</span>
              )}
            </Cell>
          ))}
        </SectionGrid>
      </Section>
    );
  }

  const national = nationalAverages?.primary;
  const disadvantaged = dropSpecial(latestValues(data, urns, 'rwm_expected_disadvantaged_pct'));
  const disadvantagedAnchor = benchmarks?.primary?.disadvantaged_rwm_expected_pct ?? null;
  // Cohort size behind the disadvantaged figure (spec §8.5): these are small
  // groups where single pupils move the percentage — show roughly how many
  // pupils the figure rests on. Taken from the SAME yearly row that supplies
  // the displayed percentage: resolving eligible_pupils and the
  // disadvantaged share independently could mix years and misstate the
  // cohort behind the figure.
  const cohorts = urns.map((urn) => {
    const rows = data[String(urn)]?.yearly_data ?? [];
    for (let i = rows.length - 1; i >= 0; i--) {
      const row = rows[i];
      if (row.rwm_expected_disadvantaged_pct != null) {
        if (row.eligible_pupils == null || row.disadvantaged_pct == null) return null;
        const cohort = Math.round((row.eligible_pupils * row.disadvantaged_pct) / 100);
        return cohort > 0 ? cohort : null;
      }
    }
    return null;
  });

  return (
    <Section
      title="How children do academically"
      how="Results from national tests and teacher assessments at the end of Year 6 — writing is assessed by teachers, not tested. Each line runs from 0–100%; the grey tick marks the England average, so dots to its right are above average."
    >
      <div className={s.card}>
        {TIER1_PRIMARY.map((spec) => (
          <Strip
            key={spec.metric}
            spec={spec}
            data={data}
            urns={urns}
            schoolNames={schoolNames}
            national={national}
            special={specialFlags}
          />
        ))}

        <details className={styles.moreMeasures}>
          <summary>More measures — grammar, punctuation &amp; spelling, science, average scaled scores</summary>
          {TIER2_PRIMARY.map((spec) => (
            <Strip
              key={spec.metric}
              spec={spec}
              data={data}
              urns={urns}
              schoolNames={schoolNames}
              national={national}
              special={specialFlags}
            />
          ))}
          <p className={styles.stripNote}>
            The scaled-score strips show the 100–120 window of the full 80–120 range; 100 is the
            expected standard. Where an England tick is missing, the official figure isn&apos;t in
            our dataset yet.
          </p>
        </details>
      </div>

      {disadvantaged.some((v) => v != null) && (
        <SectionGrid schools={schools}>
          <RowLabel tip="% of disadvantaged pupils (free school meals in the last 6 years, or looked after by the local authority) reaching the expected standard. Benchmark computed across state schools in our dataset. Based on smaller pupil groups, so a single pupil can move a school's figure noticeably.">
            Children from lower-income families
          </RowLabel>
          {schools.map((school, i) => {
            const value = disadvantaged[i];
            return (
              <Cell key={school.urn} school={school} index={i}>
                {value != null ? (
                  <>
                    <span className={s.big} style={{ fontSize: '1.1rem' }}>
                      {Math.round(value)}%
                    </span>{' '}
                    {cohorts[i] != null && (
                      <span className={s.small}>of ~{cohorts[i]} disadvantaged pupils</span>
                    )}{' '}
                    {disadvantagedAnchor != null && (
                      <Chip tone={verdict(value, disadvantagedAnchor, 5) === 'below' ? 'warn' : 'good'}>
                        {verdict(value, disadvantagedAnchor, 5) === 'above' &&
                          `Well above the ${Math.round(disadvantagedAnchor)}% state-school average`}
                        {verdict(value, disadvantagedAnchor, 5) === 'close' &&
                          `Around the ${Math.round(disadvantagedAnchor)}% state-school average`}
                        {verdict(value, disadvantagedAnchor, 5) === 'below' &&
                          `Below the ${Math.round(disadvantagedAnchor)}% state-school average`}
                      </Chip>
                    )}
                  </>
                ) : (
                  <span className={s.small}>No data</span>
                )}
              </Cell>
            );
          })}
        </SectionGrid>
      )}
    </Section>
  );
}
