import { ValidationHelpers, __, sprintf } from '@vareoncalc/calculator-base';
import { initCompactTwoStep } from '../utils/compact-two-step.js';
import { applyThemedPanels } from '../utils/theme.js';

const TRASH_ICON = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"></polyline><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path><line x1="10" y1="11" x2="10" y2="17"></line><line x1="14" y1="11" x2="14" y2="17"></line></svg>`;

const MAX_COURSES = 16;
const TEXT_DOMAIN = 'vareon-calculator-suite-lite';
const GRADE_ORDER = ['A+', 'A', 'A-', 'B+', 'B', 'B-', 'C+', 'C', 'C-', 'D+', 'D', 'D-', 'F'];
const DISTRIBUTION_ORDER = ['a', 'b', 'c', 'd', 'f'];

const GRADE_POINTS = {
  '4.0': {
    'A+': 4.0, 'A': 4.0, 'A-': 3.7,
    'B+': 3.3, 'B': 3.0, 'B-': 2.7,
    'C+': 2.3, 'C': 2.0, 'C-': 1.7,
    'D+': 1.3, 'D': 1.0, 'D-': 0.7,
    'F': 0.0
  },
  '5.0': {
    'A+': 4.0, 'A': 4.0, 'A-': 3.7,
    'B+': 3.3, 'B': 3.0, 'B-': 2.7,
    'C+': 2.3, 'C': 2.0, 'C-': 1.7,
    'D+': 1.3, 'D': 1.0, 'D-': 0.7,
    'F': 0.0
  }
};

const COURSE_LEVEL_WEIGHTS = {
  regular: 0.0,
  honors: 0.5,
  ap: 1.0
};

export function mount(container) {
  let courses = [];
  let nextId = 1;
  let twoStepInstance = null;

  container.innerHTML = `
    <div class="vareoncalc-two-step gpa-two-step" data-two-step data-two-step-mode="blind">
      <div class="vareoncalc-two-step__step vareoncalc-two-step__step--inputs" data-two-step-step="inputs">
        <div class="vareoncalc-two-step__inputs-body">
          <div class="vareoncalc-panel-input gpa-semester-entry vareoncalc-section gpa-section">
            <div class="gpa-semester-entry__section">
              <div class="vareoncalc-section__header gpa-semester-entry__header">
                <div class="gpa-scale-inline-wrap">
                  <span class="gpa-scale-label">${__('Scale:', TEXT_DOMAIN)}</span>
                  <div class="gpa-scale-inline vareoncalc-measurement-toggle" role="group" aria-label="${__('Grading Scale', TEXT_DOMAIN)}">
                    <button type="button" class="gpa-scale-inline__btn vareoncalc-measurement-toggle__btn is-active" data-grading-scale="4.0" aria-pressed="true">4.0</button>
                    <button type="button" class="gpa-scale-inline__btn vareoncalc-measurement-toggle__btn" data-grading-scale="5.0" aria-pressed="false">5.0</button>
                  </div>
                  <button
                    type="button"
                    class="gpa-scale-settings-btn"
                    id="gpa-scenarios-settings-btn"
                    aria-label="${__('Scenario settings', TEXT_DOMAIN)}"
                    aria-expanded="false"
                    aria-controls="gpa-scenarios-modal"
                  >
                    <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true" focusable="false">
                      <line x1="4" y1="21" x2="4" y2="14"></line>
                      <line x1="4" y1="10" x2="4" y2="3"></line>
                      <line x1="12" y1="21" x2="12" y2="13"></line>
                      <line x1="12" y1="9" x2="12" y2="3"></line>
                      <line x1="20" y1="21" x2="20" y2="17"></line>
                      <line x1="20" y1="13" x2="20" y2="3"></line>
                      <line x1="1" y1="14" x2="7" y2="14"></line>
                      <line x1="9" y1="9" x2="15" y2="9"></line>
                      <line x1="17" y1="16" x2="23" y2="16"></line>
                    </svg>
                  </button>
                </div>
                <div class="vareoncalc-section__title gpa-semester-entry__title">${__('Semester Entry', TEXT_DOMAIN)}</div>
                <div id="course-limit-note" class="gpa-limit-note" role="status" aria-live="polite" hidden>
                  ${__('Course limit reached (16). Remove a course to add more.', TEXT_DOMAIN)}
                </div>
                <input type="hidden" id="grading-scale" value="4.0">
              </div>

              <div id="course-headers" class="gpa-course-header">
                <div class="gpa-course-header__name">${__('Course', TEXT_DOMAIN)}</div>
                <div class="gpa-course-header__grade">${__('Grade', TEXT_DOMAIN)}</div>
                <div class="gpa-course-header__credits">${__('Credits', TEXT_DOMAIN)}</div>
                <div class="gpa-course-header__action"></div>
              </div>

              <div class="gpa-course-list" id="courses-container"></div>

              <button type="button" class="gpa-add-course-btn" id="add-course-btn">
                <span class="gpa-add-course-btn__icon">+</span>
                <span class="gpa-add-course-btn__text">${__('Add Course', TEXT_DOMAIN)}</span>
              </button>
            </div>

            <div class="gpa-step-actions">
              <button type="button" class="vareoncalc-btn" id="gpa-next-btn" data-two-step-next disabled>
                ${__('Calculate GPA', TEXT_DOMAIN)}
              </button>
            </div>
          </div>
        </div>
      </div>

      <div class="vareoncalc-two-step__step vareoncalc-two-step__step--results" data-two-step-step="results" aria-hidden="true">
        <div class="vareoncalc-two-step__results gpa-results-step">
          <div class="vareoncalc-panel-result vareoncalc-gpa-report vareoncalc-gpa-report--placeholder" id="result-panel">
            <div class="gpa-empty-state">
              <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">
                <path d="M4 4h16v16H4z"></path>
                <path d="M8 9h8M8 13h8M8 17h5"></path>
              </svg>
              <p>${__('Add courses in Step 1 to build your report card.', TEXT_DOMAIN)}</p>
            </div>
          </div>
        </div>
      </div>

      <button type="button" class="vareoncalc-two-step__blind-handle" data-two-step-toggle>
        <span class="vareoncalc-two-step__blind-handle-grip" aria-hidden="true"></span>
        <span>${__('Edit semester entry', TEXT_DOMAIN)}</span>
        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m18 15-6-6-6 6"/></svg>
      </button>

      <div class="gpa-scenario-modal" id="gpa-scenarios-modal" hidden>
        <div class="gpa-scenario-modal__backdrop" id="gpa-scenarios-modal-backdrop"></div>
        <div class="gpa-scenario-modal__container" role="dialog" aria-modal="true" aria-labelledby="gpa-scenarios-modal-title">
          <div class="gpa-scenario-modal__header">
            <div class="gpa-scenario-modal__title-group">
              <h3 class="gpa-scenario-modal__title" id="gpa-scenarios-modal-title">${__('Scenario Settings', TEXT_DOMAIN)}</h3>
              <p class="gpa-scenario-modal__subtitle">${__('Adjust cumulative and target planning inputs for GPA forecasting.', TEXT_DOMAIN)}</p>
            </div>
            <button type="button" class="gpa-scenario-modal__close" id="gpa-scenarios-modal-close" aria-label="${__('Close', TEXT_DOMAIN)}">
              <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true" focusable="false">
                <line x1="18" y1="6" x2="6" y2="18"></line>
                <line x1="6" y1="6" x2="18" y2="18"></line>
              </svg>
            </button>
          </div>

          <div class="gpa-scenario-modal__body">
            <div class="gpa-scenarios">
              <div class="gpa-form-section gpa-scenario-card vareoncalc-section gpa-section" data-scenario-card="cumulative">
                <div class="gpa-form-section__header">
                  <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true" focusable="false">
                    <path d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"></path>
                  </svg>
                  <span>${__('Add Past Semesters', TEXT_DOMAIN)}</span>
                </div>
                <div class="gpa-form-section__body" id="scenario-cumulative-panel">
                  <p class="gpa-scenario-hint">${__('Blend prior GPA and credits into a cumulative result.', TEXT_DOMAIN)}</p>
                  <div class="gpa-scenario-grid">
                    <div class="vareoncalc-field">
                      <label for="prior-gpa">${__('Prior GPA', TEXT_DOMAIN)}</label>
                      <input type="number" id="prior-gpa" min="0" max="6" step="0.01" placeholder="3.25">
                    </div>
                    <div class="vareoncalc-field">
                      <label for="prior-credits">${__('Prior Credits', TEXT_DOMAIN)}</label>
                      <input type="number" id="prior-credits" min="0" step="0.5" placeholder="30">
                    </div>
                  </div>
                </div>
              </div>

              <div class="gpa-form-section gpa-scenario-card vareoncalc-section gpa-section" data-scenario-card="target">
                <div class="gpa-form-section__header">
                  <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true" focusable="false">
                    <circle cx="12" cy="12" r="10"></circle>
                    <circle cx="12" cy="12" r="6"></circle>
                    <circle cx="12" cy="12" r="2"></circle>
                  </svg>
                  <span>${__('Target Planning', TEXT_DOMAIN)}</span>
                </div>
                <div class="gpa-form-section__body" id="scenario-target-panel">
                  <p class="gpa-scenario-hint">${__('Set a GPA target and project the grade you need next semester.', TEXT_DOMAIN)}</p>
                  <div class="gpa-scenario-grid gpa-scenario-grid--single">
                    <div class="vareoncalc-field">
                      <label for="target-gpa">${__('Target GPA', TEXT_DOMAIN)}</label>
                      <input type="number" id="target-gpa" min="0" max="6" step="0.01" placeholder="3.80">
                    </div>
                  </div>
                  <div class="gpa-scenario-note">
                    ${__('Target planning uses your current semester credit load as next semester planning load.', TEXT_DOMAIN)}
                  </div>
                  <div id="gpa-target-output" class="gpa-target-output" hidden></div>
                </div>
              </div>
            </div>
          </div>

          <div class="gpa-scenario-modal__footer">
            <button type="button" class="vareoncalc-btn" id="gpa-scenarios-modal-done">${__('Done', TEXT_DOMAIN)}</button>
          </div>
        </div>
      </div>
    </div>
  `;

  applyThemedPanels(container);

  const gradingScaleInput = container.querySelector('#grading-scale');
  const gradingScaleButtons = Array.from(container.querySelectorAll('[data-grading-scale]'));
  const courseHeaders = container.querySelector('#course-headers');
  const coursesContainer = container.querySelector('#courses-container');
  const addCourseBtn = container.querySelector('#add-course-btn');
  const nextBtn = container.querySelector('#gpa-next-btn');
  const resultPanel = container.querySelector('#result-panel');
  const courseLimitNote = container.querySelector('#course-limit-note');
  if (courseLimitNote) {
    courseLimitNote.hidden = true;
  }

  const cumulativeCard = container.querySelector('[data-scenario-card="cumulative"]');
  const priorGpaInput = container.querySelector('#prior-gpa');
  const priorCreditsInput = container.querySelector('#prior-credits');

  const targetCard = container.querySelector('[data-scenario-card="target"]');
  const targetGpaInput = container.querySelector('#target-gpa');
  const targetOutput = container.querySelector('#gpa-target-output');
  const scenariosSettingsBtn = container.querySelector('#gpa-scenarios-settings-btn');
  const scenariosModal = container.querySelector('#gpa-scenarios-modal');
  const scenariosModalBackdrop = container.querySelector('#gpa-scenarios-modal-backdrop');
  const scenariosModalClose = container.querySelector('#gpa-scenarios-modal-close');
  const scenariosModalDone = container.querySelector('#gpa-scenarios-modal-done');

  const twoStepRoot = container.querySelector('.gpa-two-step');

  const forEachTwoStepInstance = (handler) => {
    if (!twoStepInstance) {
      return;
    }
    if (Array.isArray(twoStepInstance)) {
      twoStepInstance.forEach((instance) => {
        if (instance) {
          handler(instance);
        }
      });
      return;
    }
    handler(twoStepInstance);
  };

  const refreshTwoStepLayout = () => {
    forEachTwoStepInstance((instance) => {
      if (typeof instance.refreshLayout === 'function') {
        instance.refreshLayout();
      }
    });
  };

  function isResultsStepActive() {
    return !!(twoStepRoot && twoStepRoot.dataset.step === 'results');
  }

  function focusInput(input) {
    if (!input) {
      return;
    }
    const isPreview = !!container.closest('#vareoncalc-preview-root, #vareoncalc-preview-root-design, .vareoncalc-live-preview');
    if (isPreview) {
      try {
        input.focus({ preventScroll: true });
      } catch (error) {
        // Ignore focus quirks in preview.
      }
      return;
    }
    try {
      input.focus({ preventScroll: true });
    } catch (error) {
      input.focus();
    }
  }

  function getDefaultCredits(scale) {
    return scale === '5.0' ? '4' : '3';
  }

  function setGradingScale(scale) {
    const normalized = scale === '5.0' ? '5.0' : '4.0';
    gradingScaleInput.value = normalized;
    gradingScaleButtons.forEach((button) => {
      const active = button.dataset.gradingScale === normalized;
      button.classList.toggle('is-active', active);
      button.setAttribute('aria-pressed', active ? 'true' : 'false');
    });
  }

  function updateHeaders() {
    const isWeighted = gradingScaleInput.value === '5.0';
    if (isWeighted) {
      courseHeaders.className = 'gpa-course-header gpa-course-header--weighted';
      courseHeaders.innerHTML = `
        <div class="gpa-course-header__name">${__('Course', TEXT_DOMAIN)}</div>
        <div class="gpa-course-header__grade">${__('Grade', TEXT_DOMAIN)}</div>
        <div class="gpa-course-header__level">${__('Level', TEXT_DOMAIN)}</div>
        <div class="gpa-course-header__credits">${__('Credits', TEXT_DOMAIN)}</div>
        <div class="gpa-course-header__action"></div>
      `;
      return;
    }
    courseHeaders.className = 'gpa-course-header';
    courseHeaders.innerHTML = `
      <div class="gpa-course-header__name">${__('Course', TEXT_DOMAIN)}</div>
      <div class="gpa-course-header__grade">${__('Grade', TEXT_DOMAIN)}</div>
      <div class="gpa-course-header__credits">${__('Credits', TEXT_DOMAIN)}</div>
      <div class="gpa-course-header__action"></div>
    `;
  }

  function buildGradeOptions(selected = 'A') {
    return GRADE_ORDER.map((grade) => `<option value="${grade}" ${grade === selected ? 'selected' : ''}>${grade}</option>`).join('');
  }

  function getRowInputs(rowElement) {
    return {
      nameInput: rowElement.querySelector('.course-name'),
      gradeSelect: rowElement.querySelector('.course-grade'),
      levelSelect: rowElement.querySelector('.course-level'),
      creditsInput: rowElement.querySelector('.course-credits'),
      removeBtn: rowElement.querySelector('.gpa-remove-btn')
    };
  }

  function applyGradeTint(gradeSelect) {
    if (!gradeSelect) {
      return;
    }
    const tones = ['a', 'b', 'c', 'd', 'f'];
    tones.forEach((tone) => {
      gradeSelect.classList.remove(`gpa-grade-tint--${tone}`);
    });
    gradeSelect.classList.add(`gpa-grade-tint--${getGradeTone(gradeSelect.value)}`);
  }

  function parseCourseRow(rowElement) {
    const { nameInput, gradeSelect, levelSelect, creditsInput } = getRowInputs(rowElement);
    const name = (nameInput?.value || '').trim();
    const grade = gradeSelect?.value || 'A';
    const level = levelSelect?.value || 'regular';
    const credits = parseFloat(creditsInput?.value || '');
    const hasValidCredits = Number.isFinite(credits) && credits > 0;
    const isValid = name !== '' && hasValidCredits;
    return {
      name,
      grade,
      level,
      credits: hasValidCredits ? credits : 0,
      isValid
    };
  }

  function getValidCourses() {
    return courses
      .map((course) => parseCourseRow(course.element))
      .filter((course) => course.isValid);
  }

  function hasValidCourse() {
    return getValidCourses().length > 0;
  }

  function updateCourseLimitUI() {
    const atLimit = courses.length >= MAX_COURSES;
    addCourseBtn.disabled = atLimit;
    addCourseBtn.classList.toggle('gpa-add-course-btn--disabled', atLimit);
    if (courseLimitNote) {
      courseLimitNote.hidden = !atLimit;
      courseLimitNote.setAttribute('aria-hidden', atLimit ? 'false' : 'true');
    }
  }

  function updateNextButtonState() {
    const enabled = hasValidCourse();
    nextBtn.disabled = !enabled;
    nextBtn.setAttribute('aria-disabled', enabled ? 'false' : 'true');
    if (isResultsStepActive()) {
      calculateAndRender();
    }
  }

  function createRowMarkup(id, scale, seed = {}) {
    const isWeighted = scale === '5.0';
    const defaultCredits = typeof seed.credits === 'string' || typeof seed.credits === 'number'
      ? String(seed.credits)
      : getDefaultCredits(scale);
    const defaultGrade = seed.grade || 'A';
    const defaultLevel = seed.level || 'regular';
    const defaultName = seed.name || '';
    return `
      <div class="gpa-course-row${isWeighted ? ' gpa-course-row--weighted' : ''}" data-id="${id}">
        <div class="gpa-course-row__name">
          <input type="text" class="course-name gpa-input" id="course-name-${id}" placeholder="${__('e.g. Calculus I', TEXT_DOMAIN)}" maxlength="60" value="${escapeAttribute(defaultName)}">
        </div>
        <div class="gpa-course-row__grade">
          <select class="course-grade gpa-input" id="course-grade-${id}">
            ${buildGradeOptions(defaultGrade)}
          </select>
        </div>
        ${isWeighted ? `
          <div class="gpa-course-row__level">
            <select class="course-level gpa-input" id="course-level-${id}">
              <option value="regular" ${defaultLevel === 'regular' ? 'selected' : ''}>${__('Regular', TEXT_DOMAIN)}</option>
              <option value="honors" ${defaultLevel === 'honors' ? 'selected' : ''}>${__('Honors', TEXT_DOMAIN)}</option>
              <option value="ap" ${defaultLevel === 'ap' ? 'selected' : ''}>${__('AP / IB', TEXT_DOMAIN)}</option>
            </select>
          </div>
        ` : ''}
        <div class="gpa-course-row__credits">
          <input type="number" class="course-credits gpa-input" id="course-credits-${id}" min="0" max="12" step="0.5" value="${escapeAttribute(defaultCredits)}">
        </div>
        <div class="gpa-course-row__action">
          <button type="button" class="gpa-remove-btn" data-id="${id}" title="${__('Remove course', TEXT_DOMAIN)}">
            ${TRASH_ICON}
          </button>
        </div>
      </div>
    `;
  }

  function addCourse(seed = {}, focusField = 'name') {
    if (courses.length >= MAX_COURSES) {
      updateCourseLimitUI();
      return null;
    }

    const id = nextId++;
    const scale = gradingScaleInput.value;
    const wrapper = document.createElement('div');
    wrapper.innerHTML = createRowMarkup(id, scale, seed);
    const rowElement = wrapper.firstElementChild;
    if (!rowElement) {
      return null;
    }

    coursesContainer.appendChild(rowElement);
    const course = { id, element: rowElement };
    courses.push(course);

    const { nameInput, gradeSelect, levelSelect, creditsInput, removeBtn } = getRowInputs(rowElement);
    applyGradeTint(gradeSelect);

    const handleRowChange = () => {
      if (gradeSelect) {
        applyGradeTint(gradeSelect);
      }
      updateNextButtonState();
    };

    nameInput?.addEventListener('input', handleRowChange);
    gradeSelect?.addEventListener('change', handleRowChange);
    levelSelect?.addEventListener('change', handleRowChange);
    creditsInput?.addEventListener('input', handleRowChange);

    creditsInput?.addEventListener('keydown', (event) => {
      if (event.key !== 'Tab' || event.shiftKey) {
        return;
      }
      const isLastRow = courses[courses.length - 1]?.id === id;
      if (!isLastRow || courses.length >= MAX_COURSES) {
        return;
      }
      const parsed = parseCourseRow(rowElement);
      if (!parsed.isValid) {
        return;
      }
      event.preventDefault();
      const newRow = addCourse({}, 'name');
      if (!newRow) {
        return;
      }
      const newNameInput = newRow.querySelector('.course-name');
      focusInput(newNameInput);
    });

    removeBtn?.addEventListener('click', () => {
      courses = courses.filter((item) => item.id !== id);
      rowElement.remove();
      if (courses.length === 0) {
        addCourse({}, 'name');
      }
      updateCourseLimitUI();
      updateNextButtonState();
      refreshTwoStepLayout();
    });

    updateCourseLimitUI();
    if (focusField === 'name') {
      focusInput(nameInput);
    } else if (focusField === 'credits') {
      focusInput(creditsInput);
    }
    refreshTwoStepLayout();

    return rowElement;
  }

  function captureCourses() {
    return courses.map((course) => {
      const parsed = parseCourseRow(course.element);
      const { creditsInput } = getRowInputs(course.element);
      const rawCredits = creditsInput ? creditsInput.value : '';
      return {
        name: parsed.name,
        grade: parsed.grade,
        level: parsed.level,
        credits: rawCredits === '' ? '' : rawCredits
      };
    });
  }

  function rebuildRowsForScale() {
    const snapshot = captureCourses();
    coursesContainer.innerHTML = '';
    courses = [];
    updateHeaders();
    snapshot.forEach((row) => {
      addCourse(row, null);
    });
    if (snapshot.length === 0) {
      addCourse({}, null);
    }
    updateCourseLimitUI();
    updateNextButtonState();
    refreshTwoStepLayout();
  }

  function showTargetMessage(message, type = 'info') {
    if (!message) {
      targetOutput.hidden = true;
      targetOutput.textContent = '';
      targetOutput.className = 'gpa-target-output';
      return;
    }
    targetOutput.hidden = false;
    targetOutput.className = `gpa-target-output gpa-target-output--${type}`;
    targetOutput.textContent = message;
  }

  function hasInputValue(input) {
    return !!(input && input.value.trim() !== '');
  }

  function collectScenarioState() {
    const cumulativeHasInput = hasInputValue(priorGpaInput) || hasInputValue(priorCreditsInput);
    const targetHasInput = hasInputValue(targetGpaInput);
    const state = {
      useCumulative: cumulativeHasInput,
      priorGpa: null,
      priorCredits: null,
      cumulativeValid: true,
      useTarget: targetHasInput,
      targetGpa: null,
      targetValid: true
    };

    if (state.useCumulative) {
      const priorGpa = parseInputNumber(priorGpaInput);
      const priorCredits = parseInputNumber(priorCreditsInput);

      if (!Number.isFinite(priorGpa) || priorGpa < 0 || priorGpa > 6) {
        ValidationHelpers.markInvalid(priorGpaInput);
        state.cumulativeValid = false;
      } else {
        state.priorGpa = priorGpa;
      }

      if (!Number.isFinite(priorCredits) || priorCredits < 0) {
        ValidationHelpers.markInvalid(priorCreditsInput);
        state.cumulativeValid = false;
      } else {
        state.priorCredits = priorCredits;
      }
    }

    if (state.useTarget) {
      const targetGpa = parseInputNumber(targetGpaInput);
      if (!Number.isFinite(targetGpa) || targetGpa < 0 || targetGpa > 6) {
        ValidationHelpers.markInvalid(targetGpaInput);
        state.targetValid = false;
      } else {
        state.targetGpa = targetGpa;
      }
    }

    return state;
  }

  function calculateCore() {
    const scale = gradingScaleInput.value;
    const scaleMax = scale === '5.0' ? 5.0 : 4.0;
    const isWeighted = scale === '5.0';
    const scalePoints = GRADE_POINTS[scale];
    const validCourses = getValidCourses();

    let semesterPoints = 0;
    let semesterUnweightedPoints = 0;
    let semesterCredits = 0;
    const distribution = { a: 0, b: 0, c: 0, d: 0, f: 0 };

    validCourses.forEach((course) => {
      const basePoints = scalePoints[course.grade] ?? 0;
      const weightedPoints = isWeighted ? basePoints + (COURSE_LEVEL_WEIGHTS[course.level] ?? 0) : basePoints;
      semesterCredits += course.credits;
      semesterPoints += (weightedPoints * course.credits);
      semesterUnweightedPoints += (basePoints * course.credits);
      distribution[getGradeTone(course.grade)] += 1;
    });

    if (semesterCredits <= 0) {
      return {
        hasData: false,
        scaleMax,
        distribution,
        isWeighted
      };
    }

    const semesterGpa = semesterPoints / semesterCredits;
    const unweightedGpa = isWeighted ? (semesterUnweightedPoints / semesterCredits) : semesterGpa;

    return {
      hasData: true,
      scaleMax,
      isWeighted,
      validCourses,
      distribution,
      semesterCredits,
      semesterPoints,
      semesterGpa,
      unweightedGpa
    };
  }

  function calculateAndRender() {
    ValidationHelpers.clearAllErrors(container);

    const base = calculateCore();
    if (!base.hasData) {
      renderPlaceholder(resultPanel);
      showTargetMessage('', 'info');
      refreshTwoStepLayout();
      return;
    }

    const scenario = collectScenarioState();
    let displayGpa = base.semesterGpa;
    let totalCredits = base.semesterCredits;
    let modeLabel = __('Semester GPA', TEXT_DOMAIN);
    const notes = [];

    if (scenario.useCumulative) {
      if (scenario.cumulativeValid) {
        const priorCredits = scenario.priorCredits;
        const priorPoints = scenario.priorGpa * priorCredits;
        if (priorCredits > 0) {
          totalCredits = priorCredits + base.semesterCredits;
          displayGpa = (priorPoints + base.semesterPoints) / totalCredits;
          modeLabel = __('Cumulative GPA', TEXT_DOMAIN);
        } else {
          notes.push(__('Prior credits are 0, so this remains your semester GPA.', TEXT_DOMAIN));
        }
      } else {
        notes.push(__('Enter valid prior GPA and prior credits to blend cumulative results.', TEXT_DOMAIN));
      }
    }

    const letterMeta = getLetterMeta(base.isWeighted ? base.unweightedGpa : displayGpa);

    let targetMessage = '';
    let targetType = 'info';
    if (scenario.useTarget) {
      if (!scenario.targetValid) {
        targetMessage = __('Enter a valid target GPA between 0 and 6.', TEXT_DOMAIN);
        targetType = 'warning';
      } else {
        const planningCredits = base.semesterCredits;
        let basePoints = base.semesterPoints;
        let baseCredits = base.semesterCredits;
        if (scenario.useCumulative && scenario.cumulativeValid && Number.isFinite(scenario.priorCredits) && scenario.priorCredits > 0) {
          basePoints = (scenario.priorGpa * scenario.priorCredits) + base.semesterPoints;
          baseCredits = scenario.priorCredits + base.semesterCredits;
        }

        if (scenario.targetGpa > base.scaleMax) {
          targetMessage = sprintf(
            __('Target GPA exceeds the %1$s scale.', TEXT_DOMAIN),
            base.scaleMax.toFixed(1)
          );
          targetType = 'warning';
        } else {
          const requiredGpa = (scenario.targetGpa * (baseCredits + planningCredits) - basePoints) / planningCredits;
          if (requiredGpa <= 0) {
            targetMessage = sprintf(
              __('You are already on pace for %1$s. Keep next semester at %2$s or higher.', TEXT_DOMAIN),
              scenario.targetGpa.toFixed(2),
              Math.max(requiredGpa, 0).toFixed(2)
            );
            targetType = 'success';
          } else if (requiredGpa > base.scaleMax) {
            targetMessage = sprintf(
              __('You would need %1$s next semester, which is above this %2$s scale.', TEXT_DOMAIN),
              requiredGpa.toFixed(2),
              base.scaleMax.toFixed(1)
            );
            targetType = 'warning';
          } else {
            targetMessage = sprintf(
              __('You need a %1$s next semester to reach your target.', TEXT_DOMAIN),
              requiredGpa.toFixed(2)
            );
            targetType = 'info';
          }
        }
      }
    }

    showTargetMessage(targetMessage, targetType);

    renderReportCard(resultPanel, {
      displayGpa,
      semesterGpa: base.semesterGpa,
      unweightedGpa: base.unweightedGpa,
      totalCredits,
      semesterCredits: base.semesterCredits,
      semesterPoints: base.semesterPoints,
      scaleMax: base.scaleMax,
      isWeighted: base.isWeighted,
      letterMeta,
      distribution: base.distribution,
      courseCount: base.validCourses.length,
      modeLabel,
      notes
    });

    refreshTwoStepLayout();
  }

  function syncScenarioCardState() {
    if (cumulativeCard) {
      cumulativeCard.classList.toggle('is-active', hasInputValue(priorGpaInput) || hasInputValue(priorCreditsInput));
    }
    if (targetCard) {
      targetCard.classList.toggle('is-active', hasInputValue(targetGpaInput));
    }
  }

  const modalPlaceholder = document.createComment('gpa-scenarios-modal');
  const modalThemeRoot = container.closest('.vareoncalc-root');

  const MODAL_THEME_VARS = [
    '--sc-card-bg', '--sc-card-text', '--sc-card-border',
    '--sc-input-bg', '--sc-input-border', '--sc-input-text',
    '--sc-accent', '--sc-muted-text',
    '--sc-button-bg', '--sc-button-text', '--sc-button-hover'
  ];

  function syncModalThemeVars() {
    if (!scenariosModal || !modalThemeRoot) {
      return;
    }
    const cs = getComputedStyle(modalThemeRoot);
    MODAL_THEME_VARS.forEach((prop) => {
      const value = cs.getPropertyValue(prop).trim();
      if (value) {
        scenariosModal.style.setProperty(prop, value);
      }
    });
  }

  function clearModalThemeVars() {
    if (!scenariosModal) {
      return;
    }
    MODAL_THEME_VARS.forEach((prop) => scenariosModal.style.removeProperty(prop));
  }

  function setScenariosModalState(isOpen) {
    if (!scenariosModal || !scenariosSettingsBtn) {
      return;
    }
    if (isOpen) {
      scenariosModal.parentNode.insertBefore(modalPlaceholder, scenariosModal);
      syncModalThemeVars();
      document.body.appendChild(scenariosModal);
      scenariosModal.removeAttribute('hidden');
      document.body.style.overflow = 'hidden';
    } else {
      scenariosModal.setAttribute('hidden', '');
      document.body.style.overflow = '';
      clearModalThemeVars();
      if (modalPlaceholder.parentNode) {
        modalPlaceholder.parentNode.insertBefore(scenariosModal, modalPlaceholder);
        modalPlaceholder.parentNode.removeChild(modalPlaceholder);
      }
    }
    scenariosSettingsBtn.setAttribute('aria-expanded', isOpen ? 'true' : 'false');
    scenariosSettingsBtn.classList.toggle('is-active', isOpen);
    refreshTwoStepLayout();
    if (isOpen && scenariosModalClose) {
      setTimeout(() => {
        scenariosModalClose.focus();
      }, 0);
    }
  }

  setGradingScale('4.0');
  updateHeaders();
  addCourse({}, null);
  updateCourseLimitUI();
  updateNextButtonState();

  addCourseBtn.addEventListener('click', () => {
    const row = addCourse({}, 'name');
    if (row) {
      updateNextButtonState();
    }
  });

  gradingScaleButtons.forEach((button) => {
    button.addEventListener('click', () => {
      const nextScale = button.dataset.gradingScale || '4.0';
      if (nextScale === gradingScaleInput.value) {
        return;
      }
      setGradingScale(nextScale);
      rebuildRowsForScale();
    });
  });

  nextBtn.addEventListener('click', (event) => {
    if (!hasValidCourse()) {
      event.preventDefault();
      return;
    }
    calculateAndRender();
  });
  syncScenarioCardState();

  if (scenariosSettingsBtn) {
    scenariosSettingsBtn.addEventListener('click', () => {
      setScenariosModalState(true);
    });
  }
  scenariosModalClose?.addEventListener('click', () => {
    setScenariosModalState(false);
  });
  scenariosModalDone?.addEventListener('click', () => {
    setScenariosModalState(false);
  });
  scenariosModalBackdrop?.addEventListener('click', () => {
    setScenariosModalState(false);
  });
  document.addEventListener('keydown', (event) => {
    if (event.key !== 'Escape') {
      return;
    }
    if (!scenariosModal || scenariosModal.hasAttribute('hidden')) {
      return;
    }
    event.preventDefault();
    setScenariosModalState(false);
  });
  setScenariosModalState(false);

  [priorGpaInput, priorCreditsInput, targetGpaInput].forEach((input) => {
    input?.addEventListener('input', () => {
      syncScenarioCardState();
      if (!isResultsStepActive()) {
        return;
      }
      calculateAndRender();
    });
  });

  container.addEventListener('click', (event) => {
    const editLink = event.target.closest('[data-gpa-edit-semester]');
    if (!editLink) {
      return;
    }
    const blindHandle = container.querySelector('[data-two-step-toggle]');
    if (blindHandle) {
      blindHandle.click();
    }
  });

  twoStepInstance = initCompactTwoStep(container, {
    canProceed: hasValidCourse
  });
  refreshTwoStepLayout();
}

function renderPlaceholder(panel) {
  panel.className = 'vareoncalc-panel-result vareoncalc-gpa-report vareoncalc-gpa-report--placeholder';
  panel.innerHTML = `
    <div class="gpa-empty-state">
      <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">
        <path d="M4 4h16v16H4z"></path>
        <path d="M8 9h8M8 13h8M8 17h5"></path>
      </svg>
      <p>${__('Add courses in Step 1 to build your report card.', TEXT_DOMAIN)}</p>
    </div>
  `;
  applyThemedPanels(panel);
}

function renderReportCard(panel, data) {
  const {
    displayGpa,
    semesterGpa,
    unweightedGpa,
    totalCredits,
    semesterCredits,
    semesterPoints,
    scaleMax,
    isWeighted,
    letterMeta,
    distribution,
    courseCount,
    modeLabel,
    notes
  } = data;

  const ringRadius = 66;
  const ringCircumference = 2 * Math.PI * ringRadius;
  const progressRatio = clamp(scaleMax > 0 ? (displayGpa / scaleMax) : 0, 0, 1);
  const targetOffset = (1 - progressRatio) * ringCircumference;
  const meterNow = clamp(displayGpa, 0, scaleMax);
  const meterText = sprintf(
    __('Current GPA %1$s on a %2$s scale', TEXT_DOMAIN),
    displayGpa.toFixed(2),
    scaleMax.toFixed(1)
  );

  const activeGrades = DISTRIBUTION_ORDER.filter((key) => distribution[key] > 0);

  const distributionTags = activeGrades
    .map((key) => {
      const count = distribution[key];
      const label = getDistributionLabel(key);
      const suffix = count === 1 ? '' : 's';
      return `<span class="gpa-dist-tag gpa-dist-tag--${key}"><span class="gpa-dist-tag__count">${count}</span><span class="gpa-dist-tag__label">${label}${suffix}</span></span>`;
    })
    .join('');

  const notesMarkup = notes.length > 0
    ? `<div class="gpa-report-notes">${notes.map((note) => `<div class="gpa-report-note">${note}</div>`).join('')}</div>`
    : '';

  panel.className = 'vareoncalc-panel-result vareoncalc-gpa-report';
  panel.innerHTML = `
    <div class="gpa-report-hero">
      <div class="gpa-ring-wrap">
        <div
          class="gpa-ring"
          role="meter"
          aria-valuemin="0"
          aria-valuemax="${scaleMax.toFixed(1)}"
          aria-valuenow="${meterNow.toFixed(2)}"
          aria-valuetext="${escapeAttribute(meterText)}"
        >
          <svg viewBox="0 0 160 160" aria-hidden="true" focusable="false">
            <circle class="gpa-ring__track" cx="80" cy="80" r="${ringRadius}"></circle>
            <circle
              class="gpa-ring__progress"
              cx="80"
              cy="80"
              r="${ringRadius}"
              stroke="${letterMeta.color}"
              stroke-dasharray="${ringCircumference.toFixed(2)}"
              stroke-dashoffset="${ringCircumference.toFixed(2)}"
              data-target-offset="${targetOffset.toFixed(2)}"
            ></circle>
          </svg>
          <div class="gpa-ring__center">
            <div class="gpa-ring__value">${displayGpa.toFixed(2)}</div>
            <div class="gpa-ring__scale">/ ${scaleMax.toFixed(1)} <span class="gpa-ring__letter" style="color: ${letterMeta.color};">${letterMeta.letter}</span></div>
          </div>
        </div>
      </div>

      <div class="gpa-report-hero__summary">
        <div class="gpa-report-hero__label">${modeLabel}</div>
        <div class="gpa-report-hero__gpa-value">${displayGpa.toFixed(2)}</div>
        <span class="gpa-report-hero__badge" style="color: ${letterMeta.color}; background: color-mix(in srgb, ${letterMeta.color} 14%, transparent);">${letterMeta.label}</span>
      </div>
    </div>

    <div class="gpa-report-metrics">
      <div class="gpa-stat-card">
        <span class="gpa-stat-card__label">${__('Semester GPA', TEXT_DOMAIN)}</span>
        <span class="gpa-stat-card__value">${semesterGpa.toFixed(2)}</span>
      </div>
      <div class="gpa-stat-card">
        <span class="gpa-stat-card__label">${__('Semester Credits', TEXT_DOMAIN)}</span>
        <span class="gpa-stat-card__value">${semesterCredits.toFixed(1)}</span>
      </div>
      <div class="gpa-stat-card">
        <span class="gpa-stat-card__label">${__('Grade Points', TEXT_DOMAIN)}</span>
        <span class="gpa-stat-card__value">${semesterPoints.toFixed(1)}</span>
      </div>
      ${isWeighted ? `
      <div class="gpa-stat-card">
        <span class="gpa-stat-card__label">${__('Unweighted GPA', TEXT_DOMAIN)}</span>
        <span class="gpa-stat-card__value">${unweightedGpa.toFixed(2)}</span>
      </div>
      ` : ''}
    </div>

    <div class="gpa-distribution">
      <div class="gpa-distribution__label">${__('Grade Distribution', TEXT_DOMAIN)}</div>
      <div class="gpa-distribution__tags">
        ${distributionTags || `<span class="gpa-dist-tag gpa-dist-tag--empty"><span class="gpa-dist-tag__label">${__('No graded courses yet', TEXT_DOMAIN)}</span></span>`}
      </div>
    </div>
    ${notesMarkup}

    <div class="gpa-edit-semester-wrap">
      <button type="button" class="gpa-edit-semester-link" data-gpa-edit-semester>
        ${__('Edit semester entry', TEXT_DOMAIN)}
        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m9 18 6-6-6-6"/></svg>
      </button>
    </div>
  `;

  const progressRing = panel.querySelector('.gpa-ring__progress');
  if (progressRing) {
    const target = progressRing.getAttribute('data-target-offset');
    requestAnimationFrame(() => {
      progressRing.style.strokeDashoffset = target || '0';
    });
  }
  applyThemedPanels(panel);
}

function parseInputNumber(input) {
  if (!input) {
    return NaN;
  }
  const raw = input.value.trim();
  if (raw === '') {
    return NaN;
  }
  return parseFloat(raw);
}

function getGradeTone(grade) {
  if (typeof grade !== 'string' || grade.length === 0) {
    return 'f';
  }
  const first = grade.charAt(0).toUpperCase();
  if (first === 'A') {
    return 'a';
  }
  if (first === 'B') {
    return 'b';
  }
  if (first === 'C') {
    return 'c';
  }
  if (first === 'D') {
    return 'd';
  }
  return 'f';
}

function getDistributionLabel(key) {
  if (key === 'a') {
    return 'A';
  }
  if (key === 'b') {
    return 'B';
  }
  if (key === 'c') {
    return 'C';
  }
  if (key === 'd') {
    return 'D';
  }
  return 'F';
}

function getLetterMeta(gpa) {
  if (gpa >= 3.85) {
    return { letter: 'A', label: __('Excellent', TEXT_DOMAIN), color: '#16a34a' };
  }
  if (gpa >= 3.5) {
    return { letter: 'A-', label: __('Very Good', TEXT_DOMAIN), color: '#22c55e' };
  }
  if (gpa >= 3.15) {
    return { letter: 'B+', label: __('Good', TEXT_DOMAIN), color: '#2563eb' };
  }
  if (gpa >= 2.85) {
    return { letter: 'B', label: __('Above Average', TEXT_DOMAIN), color: '#3b82f6' };
  }
  if (gpa >= 2.5) {
    return { letter: 'B-', label: __('Solid', TEXT_DOMAIN), color: '#60a5fa' };
  }
  if (gpa >= 2.15) {
    return { letter: 'C+', label: __('Fair', TEXT_DOMAIN), color: '#f59e0b' };
  }
  if (gpa >= 1.85) {
    return { letter: 'C', label: __('Average', TEXT_DOMAIN), color: '#fbbf24' };
  }
  if (gpa >= 1.5) {
    return { letter: 'C-', label: __('Needs Work', TEXT_DOMAIN), color: '#f97316' };
  }
  if (gpa >= 1.0) {
    return { letter: 'D', label: __('At Risk', TEXT_DOMAIN), color: '#ea580c' };
  }
  return { letter: 'F', label: __('Failing', TEXT_DOMAIN), color: '#dc2626' };
}

function clamp(value, min, max) {
  return Math.min(Math.max(value, min), max);
}

function escapeAttribute(value) {
  return String(value)
    .replace(/&/g, '&amp;')
    .replace(/"/g, '&quot;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;');
}
