import data from './portfolio.mjs';

const { identity: person, ui, sections, projects } = data;
const escape = value => String(value).replace(/[&<>"']/g, char => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[char]));
const starIcon = '<svg viewBox="0 0 32 32" aria-hidden="true"><path d="m16 1 3.5 11.5L31 16l-11.5 3.5L16 31l-3.5-11.5L1 16l11.5-3.5Z" fill="currentColor"/></svg>';
let selectedSection = 0;
let openSection = 0;
let selectedProject = 0;
let dialPosition = 0;
let dragging = false;
let previousAngle = 0;
const reducedMotion = matchMedia('(prefers-reduced-motion: reduce)');

// Fixed, original geometric star field; no location, time, or astronomy claims.
const points = Array.from({ length: 43 }, (_, index) => ({
  x: 18 + ((index * 137 + 31) % 342), y: 15 + ((index * 73 + 47) % 177),
  r: index % 7 === 0 ? 1.65 : 0.8, opacity: 0.2 + (index % 5) * 0.1
}));

document.querySelector('#app').innerHTML = `
  <a class="skip-link" href="#reading-title">${escape(ui.skip)}</a>
  <div class="site-shell">
    <header class="site-header">
      <a class="identity" href="./" aria-label="${escape(person.name)}">
        <span class="identity-mark">${starIcon}</span>
        <span><strong>${escape(person.name)}</strong><small>${escape(person.role)}</small></span>
      </a>
      <a class="text-link" href="./text.html">${escape(ui.plainView)} <span aria-hidden="true">↗</span></a>
    </header>
    <main>
      <div class="introduction">
        <h1>${escape(person.headline[0])}<br><em>${escape(person.headline[1])}</em></h1>
        <p>${escape(person.introduction)}</p>
      </div>
      <div class="observatory-layout">
        <div class="instrument-column">
          <section class="instrument" aria-label="${escape(ui.instrumentLabel)}">
            <div class="housing-top"><span>${escape(person.title)}</span><span class="top-symbol" aria-hidden="true">✳</span></div>
            <div class="glass">
              <div class="screen-top"><span>${escape(ui.index)}</span><span class="signal" aria-hidden="true"><i></i><i></i><i></i></span></div>
              <div class="star-chart" aria-label="${escape(ui.mapLabel)}">
                <svg class="chart-grid" viewBox="0 0 380 218" aria-hidden="true">
                  <defs><radialGradient id="map-glow"><stop stop-color="#9aaf70" stop-opacity=".12"/><stop offset="1" stop-color="#9aaf70" stop-opacity="0"/></radialGradient></defs>
                  <ellipse cx="190" cy="109" rx="181" ry="108" fill="url(#map-glow)"/>
                  <g fill="none" stroke="#abc391" stroke-opacity=".13" stroke-width=".75"><ellipse cx="190" cy="109" rx="135" ry="82"/><ellipse cx="190" cy="109" rx="83" ry="82"/><ellipse cx="190" cy="109" rx="31" ry="82"/><path d="M55 109h270M67 75h246M67 143h246"/></g>
                  <g fill="#d5e5bf">${points.map(p => `<circle cx="${p.x}" cy="${p.y}" r="${p.r}" opacity="${p.opacity}"/>`).join('')}</g>
                  <g class="constellation-lines" fill="none" stroke="#a8c58b" stroke-width="1.1"><path d="M105 85 184 58 258 109 159 153 105 85 72 141M184 58 216 23M258 109 304 155M159 153 122 190"/><circle cx="184" cy="58" r="2" fill="#ccddbb"/><circle cx="72" cy="141" r="2" fill="#ccddbb"/><circle cx="216" cy="23" r="2" fill="#ccddbb"/><circle cx="304" cy="155" r="2" fill="#ccddbb"/><circle cx="122" cy="190" r="2" fill="#ccddbb"/></g>
                </svg>
                <div class="project-stars">
                  ${projects.map((p, i) => `<button class="project-star star-${i}" data-star="${i}" aria-label="${escape(ui.projectStar)} ${escape(p.title)}" aria-pressed="${i === 0}"><span class="star-core" aria-hidden="true"></span><span class="star-number" aria-hidden="true">${escape(p.number)}</span></button>`).join('')}
                </div>
                <div class="map-caption"><span id="map-project">${escape(projects[0].shortTitle)}</span><span aria-hidden="true">↗</span></div>
              </div>
              <nav class="screen-navigation" aria-label="${escape(ui.dialLabel)}">
                ${sections.map((s, i) => `<button data-section="${i}" class="section-button ${i === 0 ? 'is-selected is-open' : ''}" aria-pressed="${i === 0}"><small>${escape(s.number)}</small>${escape(s.label)}<span class="section-dot" aria-hidden="true"></span></button>`).join('')}
              </nav>
            </div>
            <div class="hardware">
              <div class="hardware-buttons">
                <button id="next-section" class="tactile-button" aria-label="${escape(ui.nextLabel)}"><span aria-hidden="true">→</span> ${escape(ui.next)}</button>
                <button id="open-section" class="tactile-button open-button" aria-label="${escape(ui.openLabel)}"><span aria-hidden="true">↗</span> ${escape(ui.open)}</button>
                <span class="button-help">${escape(ui.instruction)}</span>
              </div>
              <div class="dial-assembly">
                <div class="dial-ticks" aria-hidden="true"><span>I</span><span>II</span><span>III</span></div>
                <div class="dial" id="dial-surface">
                  <div class="dial-metal"><div class="dial-face"><span class="dial-notch"></span><span class="dial-center">${starIcon}</span></div></div>
                  <input id="section-dial" type="range" min="0" max="2" step="1" value="0" aria-label="${escape(ui.dialLabel)}" aria-valuetext="${escape(sections[0].label)}" aria-describedby="dial-instructions">
                </div>
                <span class="dial-caption">${escape(ui.dialCaption)}</span>
              </div>
            </div>
            <div class="housing-bottom"><span>${escape(person.edition)}</span><span class="speaker" aria-hidden="true">•••••</span></div>
          </section>
          <div class="instrument-footnote"><span class="status-light" aria-hidden="true"></span><span>${escape(ui.tuned)} <strong id="tuned-label">${escape(sections[0].label)}</strong></span><span class="footnote-number" aria-hidden="true">01 — 03</span></div>
          <p id="dial-instructions" class="dial-instructions">${escape(ui.instructionsDetail)}</p>
        </div>
        <div class="reading-column">
          <div class="reading-kicker"><span>${escape(ui.fieldNotes)}</span><span id="reading-section-number">01 / 03</span></div>
          <section id="reading-content" aria-labelledby="reading-title"></section>
        </div>
      </div>
    </main>
    <footer class="site-footer"><span>${escape(person.footer)}</span><span>${escape(person.fictionalNote)}</span></footer>
  </div>
  <div id="announcements" class="sr-only" role="status" aria-live="polite" aria-atomic="true"></div>
`;

const dial = document.querySelector('#section-dial');
const dialSurface = document.querySelector('#dial-surface');
const instrument = document.querySelector('.instrument');
const reading = document.querySelector('#reading-content');

function marineArt(project) {
  return `<svg viewBox="0 0 560 178" role="img" aria-label="${escape(project.annotation)}"><defs><linearGradient id="sea" x2="1" y2="1"><stop stop-color="#21494a"/><stop offset="1" stop-color="#102d30"/></linearGradient></defs><rect width="560" height="178" fill="url(#sea)"/><g fill="none" stroke="#9abdb0" stroke-width="1" opacity=".26">${Array.from({ length: 8 }, (_, i) => `<path d="M${-80 + i * 12} 190 C${20 + i * 15} ${95 - i * 8},${200 + i * 12} ${229 - i * 10},${256 + i * 15} ${64 - i * 11} S${409 + i * 12} ${25 - i * 6},${610 + i * 7} ${-18 + i * 10}"/>`).join('')}</g><g stroke="#c1d5b5" fill="none"><path stroke-dasharray="2 5" opacity=".4" d="M38 118H519M146 40V142M400 40V142"/><path d="M38 117C86 117 107 64 150 68S227 138 279 124 339 63 394 67 473 129 521 103" stroke-width="2"/></g><circle cx="150" cy="68" r="15" fill="#cadcb5" opacity=".09"/><circle cx="150" cy="68" r="5" fill="#d9e7c6"/><circle cx="150" cy="68" r="9" stroke="#d9e7c6" fill="none" opacity=".5"/><g fill="#c8d5cd" font-family="monospace" font-size="11"><text x="22" y="26">${escape(project.diagram.left)}</text><text x="538" y="26" text-anchor="end">${escape(project.diagram.right)}</text><text x="38" y="157">${escape(project.diagram.bottom)}</text><text x="522" y="157" text-anchor="end">${escape(project.diagram.end)}</text></g></svg>`;
}

function typeArt(project) {
  return `<svg viewBox="0 0 560 178" role="img" aria-label="${escape(project.annotation)}"><rect width="560" height="178" fill="#b79472"/><g fill="none" stroke="#342921" opacity=".2"><path d="M22 54h516M22 144h516M112 38v118M442 38v118"/></g><text x="280" y="132" text-anchor="middle" fill="#352e29" font-size="112" font-family="Georgia,serif" letter-spacing="14">${escape(project.diagram.word)}</text><g fill="#30291f" font-family="monospace" font-size="11"><text x="22" y="26">${escape(project.diagram.left)}</text><text x="538" y="26" text-anchor="end">${escape(project.diagram.right)}</text></g><path d="M488 93h38m-7-7 8 7-8 7" fill="none" stroke="#352e29"/></svg>`;
}

function gear(cx, cy, radius, teeth, phase = 0) {
  const pts = Array.from({ length: teeth * 4 }, (_, index) => {
    const angle = phase + index / (teeth * 4) * Math.PI * 2;
    const r = index % 4 < 2 ? radius : radius - 7;
    return `${cx + Math.cos(angle) * r},${cy + Math.sin(angle) * r}`;
  }).join(' ');
  return `<polygon points="${pts}" fill="none" stroke="#c69b73" stroke-width="1.3"/><circle cx="${cx}" cy="${cy}" r="${radius * .48}" fill="none" stroke="#c69b73" opacity=".5"/><circle cx="${cx}" cy="${cy}" r="4" fill="#d5b187"/><path d="M${cx - radius + 15} ${cy}h${(radius - 15) * 2}M${cx} ${cy - radius + 15}v${(radius - 15) * 2}" stroke="#c69b73" opacity=".3"/>`;
}

function mechanicalArt(project) {
  return `<svg viewBox="0 0 560 178" role="img" aria-label="${escape(project.annotation)}"><rect width="560" height="178" fill="#302e2a"/><g stroke="#ad9679" opacity=".12">${Array.from({ length: 18 }, (_, i) => `<path d="M${i * 32} 36v126"/>`).join('')}<path d="M22 61h516M22 93h516M22 125h516M22 157h516"/></g>${gear(213, 98, 60, 18)}${gear(296, 98, 30, 9, .15)}${gear(349, 98, 30, 9, .5)}<path d="M156 98H96m0 0 8-7m-8 7 8 7M379 98h78m0 0-8-7m8 7-8 7" stroke="#d5b187" fill="none"/><g fill="#d3bc9c" font-family="monospace" font-size="11"><text x="22" y="26">${escape(project.diagram.left)}</text><text x="538" y="26" text-anchor="end">${escape(project.diagram.right)}</text><text x="95" y="126">${escape(project.diagram.bottom)}</text><text x="422" y="126">${escape(project.diagram.end)}</text></g></svg>`;
}

function renderContent() {
  reading.classList.toggle('work-view', openSection === 0);
  document.querySelector('#reading-section-number').textContent = `${sections[openSection].number} / 03`;
  if (openSection === 0) {
    const p = projects[selectedProject];
    const art = p.type === 'marine' ? marineArt(p) : p.type === 'type' ? typeArt(p) : mechanicalArt(p);
    reading.innerHTML = `<h2 id="reading-title" tabindex="-1">${escape(ui.workHeading)}</h2>
      <div class="project-choices" role="group" aria-label="${escape(ui.projectNavigation)}">${projects.map((project, index) => `<button class="project-choice ${index === selectedProject ? 'active' : ''}" data-project="${index}" aria-pressed="${index === selectedProject}"><span>${escape(project.number)}</span>${escape(project.title)}<span class="project-arrow" aria-hidden="true">↗</span></button>`).join('')}</div>
      <article class="project-detail" data-project-id="${escape(p.id)}">
        <div class="project-meta"><span>${escape(p.category)}</span><span>${escape(ui.demoLabel)}</span></div>
        <h3>${escape(p.title)} <span>${escape(p.year)}</span></h3>
        <p class="project-description">${escape(p.description)}</p>
        <figure class="project-art">${art}<figcaption><span>${escape(p.annotation)}</span><span>${escape(ui.artNote)}</span></figcaption></figure>
        <dl class="project-facts"><div><dt>${escape(ui.role)}</dt><dd>${escape(p.role)}</dd></div><div><dt>${escape(ui.format)}</dt><dd>${escape(p.format)}</dd></div></dl>
        <p class="project-context">${escape(p.detail)}</p>
      </article>`;
  } else if (openSection === 1) {
    reading.innerHTML = `<h2 id="reading-title" tabindex="-1">${escape(ui.aboutHeading)}</h2><div class="about-content"><div class="about-monogram" aria-hidden="true">${escape(person.initials)}<span>${starIcon}</span></div><p class="eyebrow">${escape(ui.aboutLabel)}</p>${data.about.paragraphs.map(p => `<p>${escape(p)}</p>`).join('')}<div class="principles">${data.about.principles.map((p, i) => `<div><span class="principle-number">0${i + 1}</span><p><strong>${escape(p.title)}</strong><span>${escape(p.text)}</span></p></div>`).join('')}</div></div>`;
  } else {
    reading.innerHTML = `<h2 id="reading-title" tabindex="-1">${escape(ui.contactHeading)}</h2><div class="contact-content"><div class="contact-symbol" aria-hidden="true">${starIcon}</div><p class="eyebrow">${escape(ui.contactOverline)}</p><p>${escape(data.contact.paragraph)}</p><div class="contact-address"><span>${escape(ui.contactLabel)}</span><p>${escape(person.contact)}</p></div><p class="contact-note">${escape(ui.contactNote)}</p><p class="fictional-label">${escape(person.fictionalNote)}</p></div>`;
  }
}

function announce(message) {
  document.querySelector('#announcements').textContent = message;
}

function setDialPosition(position, shouldAnnounce = true) {
  dialPosition = Math.max(0, Math.min(2, position));
  instrument.style.setProperty('--turn', `${dialPosition * 120}deg`);
  instrument.style.setProperty('--chart-turn', `${dialPosition * 8 - 8}deg`);
  instrument.style.setProperty('--chart-x', `${dialPosition * 3 - 3}px`);
  const next = Math.round(dialPosition);
  const changed = next !== selectedSection;
  selectedSection = next;
  dial.value = String(next);
  dial.setAttribute('aria-valuetext', sections[next].label);
  document.querySelector('#tuned-label').textContent = sections[next].label;
  document.querySelectorAll('[data-section]').forEach((button, index) => {
    button.classList.toggle('is-selected', index === next);
    button.classList.toggle('is-open', index === openSection);
    button.setAttribute('aria-pressed', String(index === openSection));
  });
  document.querySelector('#open-section').setAttribute('aria-label', `${ui.openLabel}: ${sections[next].label}`);
  if (changed && shouldAnnounce) announce(`${ui.tuned} ${sections[next].label}. ${ui.openLabel}.`);
}

function openSelected({ focus = false } = {}) {
  openSection = selectedSection;
  renderContent();
  setDialPosition(selectedSection, false);
  announce(sections[openSection].label);
  if (focus) {
    const heading = document.querySelector('#reading-title');
    heading.focus({ preventScroll: true });
    heading.scrollIntoView({ block: 'nearest', behavior: reducedMotion.matches ? 'instant' : 'smooth' });
  }
}

function selectProject(index, source) {
  selectedProject = index;
  openSection = 0;
  setDialPosition(0, false);
  document.querySelector('#map-project').textContent = projects[index].shortTitle;
  document.querySelectorAll('[data-star]').forEach((button, i) => button.setAttribute('aria-pressed', String(index === i)));
  renderContent();
  if (source === 'list') document.querySelector(`[data-project="${index}"]`).focus({ preventScroll: true });
  announce(`${projects[index].title}. ${ui.demoLabel}.`);
}

document.querySelectorAll('[data-section]').forEach(button => button.addEventListener('click', () => {
  setDialPosition(Number(button.dataset.section), false);
  openSelected({ focus: true });
}));
document.querySelectorAll('[data-star]').forEach(button => button.addEventListener('click', () => selectProject(Number(button.dataset.star), 'star')));
reading.addEventListener('click', event => {
  const button = event.target.closest('[data-project]');
  if (button) selectProject(Number(button.dataset.project), 'list');
});
document.querySelector('#next-section').addEventListener('click', () => setDialPosition((selectedSection + 1) % sections.length));
document.querySelector('#open-section').addEventListener('click', () => openSelected({ focus: true }));

function pointerAngle(event) {
  const rect = dialSurface.getBoundingClientRect();
  return Math.atan2(event.clientY - rect.top - rect.height / 2, event.clientX - rect.left - rect.width / 2) * 180 / Math.PI;
}
dialSurface.addEventListener('pointerdown', event => {
  if (event.button !== 0) return;
  event.preventDefault();
  dial.focus({ preventScroll: true });
  dialSurface.setPointerCapture(event.pointerId);
  previousAngle = pointerAngle(event);
  dragging = true;
  instrument.classList.add('is-turning');
});
dialSurface.addEventListener('pointermove', event => {
  if (!dragging) return;
  const angle = pointerAngle(event);
  let difference = angle - previousAngle;
  if (difference > 180) difference -= 360;
  if (difference < -180) difference += 360;
  previousAngle = angle;
  setDialPosition(dialPosition + difference / 120);
});
function finishDrag() {
  if (!dragging) return;
  dragging = false;
  instrument.classList.remove('is-turning');
  setDialPosition(selectedSection, false);
}
dialSurface.addEventListener('pointerup', finishDrag);
dialSurface.addEventListener('pointercancel', finishDrag);
dialSurface.addEventListener('lostpointercapture', finishDrag);
dial.addEventListener('keydown', event => {
  const forward = event.key === 'ArrowRight' || event.key === 'ArrowUp';
  const backward = event.key === 'ArrowLeft' || event.key === 'ArrowDown';
  if (forward || backward || event.key === 'Home' || event.key === 'End') {
    event.preventDefault();
    setDialPosition(event.key === 'Home' ? 0 : event.key === 'End' ? 2 : selectedSection + (forward ? 1 : -1));
  } else if (event.key === 'Enter' || event.key === ' ') {
    event.preventDefault();
    openSelected({ focus: true });
  }
});
// Preserve native range accessibility events from assistive technologies.
dial.addEventListener('input', () => setDialPosition(Number(dial.value)));
document.querySelector('.skip-link').addEventListener('click', () => document.querySelector('#reading-title').focus());

renderContent();
setDialPosition(0, false);
