import type { Props } from "./schema";

const joinIds = (...parts: (string | number)[]) =>
  parts.map((part) => String(part).replace(/[_-]/g, (c) => `_${c.charCodeAt(0).toString(16)}_`)).join("-");

const fmt = (n: number) => Number.isInteger(n) ? n.toLocaleString("ja-JP") : n.toLocaleString("ja-JP", { maximumFractionDigits: 2 });
const wrap = (text: string, width: number) => Array.from({ length: Math.ceil([...text].length / width) }, (_, i) => [...text].slice(i * width, (i + 1) * width).join(""));

export default function Template(d: Props) {
  const titleLines = wrap(d.title, 56);
  const subtitleLines = d.subtitle ? wrap(d.subtitle, 80) : [];
  const titleY = 48;
  const subtitleY = titleY + titleLines.length * 25 + 5;
  const noteY = subtitleY + subtitleLines.length * 18 + 14;
  const top = noteY + 80;
  const bottom = Math.min(555, top + 310);
  const left = 150;
  const right = 990;
  const step = (right - left) / (d.dimensions.length - 1);
  const xs = d.dimensions.map((_, i) => left + step * i);
  const y = (value: number, dimension: number) => bottom -
    (value - d.dimensions[dimension].min) / (d.dimensions[dimension].max - d.dimensions[dimension].min) * (bottom - top);
  const focus = d.profiles.find(profile => profile.label === d.focusProfile)!;
  const endpointLabels = d.profiles.map((profile, index) => ({
    profile,
    index,
    actualY: y(profile.values[d.dimensions.length - 1], d.dimensions.length - 1),
  })).sort((a, b) => a.actualY - b.actualY);
  const labelGap = endpointLabels.length > 1 ? (bottom - top) / (endpointLabels.length - 1) : 0;

  return <section className="asset parallel">
    <style>{`.parallel{font-family:var(--font-sans);color:var(--color-on-surface);background:var(--color-surface);max-width:var(--container-slide);margin:auto;padding:2rem;line-height:1.5;font-size:var(--text-body-sm)}.parallel *{box-sizing:border-box}.parallel h1{font-size:var(--text-h2);line-height:1.3;margin:0}.muted{color:var(--color-secondary)}.plot{display:block;width:100%;height:auto}.plot .svg-title,.plot .svg-subtitle{display:none}.profile-table{width:100%;border-collapse:collapse;margin-top:1.5rem;font-variant-numeric:tabular-nums}.profile-table th,.profile-table td{padding:.65rem .55rem;border-bottom:1px solid var(--color-outline);text-align:right;overflow-wrap:anywhere}.profile-table th{color:var(--color-secondary)}.profile-table th:first-child,.profile-table td:first-child{text-align:left}.focus-row{font-weight:700;background:var(--color-surface-subtle)}.note{margin-top:1rem;color:var(--color-secondary)}@media(max-width:640px){.parallel{padding:1rem}.parallel h1{font-size:var(--text-h3)}.plot{display:none}.profile-table,.profile-table tbody,.profile-table tr,.profile-table td{display:block}.profile-table thead{display:none}.profile-table tr{padding:.75rem 0;border-bottom:1px solid var(--color-outline)}.profile-table td{border:0;padding:.2rem 0;text-align:left!important}.profile-table td:not(:first-child){display:inline-block;margin-right:.75rem}.profile-table td:not(:first-child)::before{content:attr(data-label) ": ";color:var(--color-secondary)}}`}</style>
    <header><p className="muted">PARALLEL COORDINATES · 値域ごとに正規化して配置</p>
      <h1>{titleLines.map((line, i) => <span key={i}>{line}{i + 1 < titleLines.length && <br />}</span>)}</h1>
      {d.subtitle && <p className="muted">{d.subtitle}</p>}
    </header>
    <svg className="plot" data-layout-still="true" xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720" role="img" aria-label="複数の対象を値域ごとに正規化した平行座標図">
      <rect width="1280" height="720" fill="var(--color-surface)" />
      {titleLines.map((line, i) => <text key={`title-${i}`} className="svg-title" x="64" y={titleY + i * 25} fontSize="20" fontWeight="700" fill="var(--color-on-surface)">{line}</text>)}
      {subtitleLines.map((line, i) => <text key={`subtitle-${i}`} className="svg-subtitle" x="64" y={subtitleY + i * 18} fontSize="14" fill="var(--color-secondary)">{line}</text>)}
      <text x="64" y={noteY} fontSize="14" fill="var(--color-secondary)">強調：{d.focusProfile}　／　各軸を指定した最小〜最大で正規化</text>
      {[0, 0.5, 1].map((fraction, i) => {
        const gy = bottom - (bottom - top) * fraction;
        return <line key={i} x1={left} y1={gy} x2={right} y2={gy} stroke="var(--color-outline)" strokeWidth="1" strokeDasharray={i === 1 ? "3 5" : undefined} />;
      })}
      {d.dimensions.map((dimension, i) => <g key={dimension.label}>
        <line x1={xs[i]} y1={top} x2={xs[i]} y2={bottom} stroke="var(--color-outline)" strokeWidth="2" />
        <text x={xs[i]} y={top - 56} textAnchor="middle" fontSize="15" fontWeight="700" fill="var(--color-on-surface)">{dimension.label}</text>
        <text x={xs[i]} y={top - 38} textAnchor="middle" fontSize="12" fill="var(--color-secondary)">{dimension.unit}</text>
        <text x={xs[i]} y={top - 18} textAnchor="middle" fontSize="11" fill="var(--color-secondary)">{fmt(dimension.max)}</text>
        <text x={xs[i]} y={bottom + 37} textAnchor="middle" fontSize="11" fill="var(--color-secondary)">{fmt(dimension.min)}</text>
      </g>)}
      {d.profiles.filter(profile => profile.label !== d.focusProfile).map(profile => <polyline key={profile.label} data-profile={profile.label} points={profile.values.map((value, i) => `${xs[i]},${y(value, i)}`).join(" ")} fill="none" stroke="var(--color-secondary)" strokeWidth="2" strokeOpacity="0.48" />)}
      {focus && <polyline data-profile={focus.label} points={focus.values.map((value, i) => `${xs[i]},${y(value, i)}`).join(" ")} fill="none" stroke="var(--color-tertiary)" strokeWidth="4" />}
      {d.profiles.map(profile => profile.values.map((value, i) => <circle key={joinIds(profile.label, i)} cx={xs[i]} cy={y(value, i)} r={profile.label === d.focusProfile ? 6 : 3.5} fill={profile.label === d.focusProfile ? "var(--color-tertiary)" : "var(--color-secondary)"} />))}
      {endpointLabels.map(({ profile, index, actualY }, rank) => {
        const labelY = top + rank * labelGap;
        const id = String(index + 1).padStart(2, "0");
        return <g key={`endpoint-${profile.label}`}>
          <line x1={right + 3} y1={actualY} x2={right + 14} y2={labelY} stroke="var(--color-secondary)" strokeWidth="1" />
          <line x1={right + 14} y1={labelY} x2={right + 21} y2={labelY} stroke="var(--color-secondary)" strokeWidth="1" />
          <text x={right + 26} y={labelY + 4} fontSize="12" fontWeight="700" fill={profile.label === d.focusProfile ? "var(--color-tertiary)" : "var(--color-secondary)"}>{id}</text>
        </g>;
      })}
      <text x="64" y="690" fontSize="13" fill="var(--color-secondary)">軸の順序を変えると交差の見え方も変わります。相関や因果の証拠としては使わないでください。</text>
    </svg>
    <table className="profile-table"><thead><tr><th>対象</th>{d.dimensions.map(axis => <th key={axis.label}>{axis.label}（{axis.unit}）</th>)}</tr></thead><tbody>
      {d.profiles.map((profile, index) => <tr key={profile.label} className={profile.label === d.focusProfile ? "focus-row" : ""} data-profile-row><td><strong>{String(index + 1).padStart(2, "0")}</strong> {profile.label}</td>{profile.values.map((value, i) => <td key={d.dimensions[i].label} data-label={`${d.dimensions[i].label} (${d.dimensions[i].unit})`}>{fmt(value)}</td>)}</tr>)}
    </tbody></table>
    <p className="note">各指標は設定した範囲の中で位置を正規化しています。実数値は表で確認できます。</p>
  </section>;
}
