// Hero, Section, Stats, RepoCard, Timeline, ContactForm
const Wrap = ({ children, style }) => (
  <div style={{ maxWidth: 'var(--container)', margin: '0 auto', padding: '0 40px', ...style }}>{children}</div>
);

const Eyebrow = ({ n, children }) => (
  <div className="t-eyebrow" style={{ display: 'flex', gap: 12 }}><span style={{ color: 'var(--fg1)' }}>{n}</span><span>— {children}</span></div>
);

const SectionHead = ({ n, en, ko }) => (
  <div style={{ marginBottom: 48 }}>
    <Eyebrow n={n}>{en}</Eyebrow>
    <h2 style={{ font: '800 72px/0.95 var(--font-sans)', letterSpacing: '-0.045em', margin: '16px 0 0' }}>{en}.</h2>
    <div className="t-ko-display" style={{ fontSize: 28, color: 'var(--fg2)', marginTop: 8 }}>{ko}</div>
  </div>
);

const Hero = ({ go }) => (
  <Wrap style={{ paddingTop: 96, paddingBottom: 96 }}>
    <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 32 }}>
      <span style={{ width: 8, height: 8, borderRadius: 99, background: 'var(--fg1)' }} />
      <span style={{ font: '500 13px var(--font-mono)', color: 'var(--fg2)' }}>IDIS · Tech Sales · Self-taught Developer</span>
    </div>
    <h1 className="t-hero" style={{ margin: 0 }}>IDISMAN<span style={{ color: 'var(--gray-300)' }}>.</span></h1>
    <div style={{ display: 'grid', gridTemplateColumns: '1.3fr 1fr', gap: 64, marginTop: 48, alignItems: 'end' }}>
      <div>
        <div className="t-ko-display" style={{ fontSize: 44 }}>2011년 입사<br />저는 아이디스맨입니다.</div>
        <p style={{ fontSize: 20, color: 'var(--fg2)', margin: '20px 0 0', lineHeight: 1.5, maxWidth: 560 }}>
          16 years in video security — proposals, system design and PM. When the field needs a tool, I build it myself.
        </p>
      </div>
      <div style={{ display: 'flex', gap: 12, justifyContent: 'flex-end' }}>
        <Button size="lg" iconRight="arrow-right" onClick={() => go('contact')}>Let's talk</Button>
        <Button size="lg" variant="secondary" onClick={() => go('projects')}>프로젝트 보기</Button>
      </div>
    </div>
  </Wrap>
);

const Stats = () => (
  <Wrap style={{ paddingBottom: 96 }}>
    <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4,1fr)', borderTop: '1.5px solid var(--fg1)' }}>
      {[['16', '+', 'Years', '영상보안 기술영업'], ['2011', '', 'IDIS', '아이디스 입사'], [String(PROJECT_DATES.length), '', 'Tools', '업무용으로 직접 만든 도구'], ['5', 'yr', 'Self-taught', 'Python · Django · LLM']].map(([n, s, en, ko]) => (
        <div key={en} style={{ padding: '24px 24px 0 0' }}>
          <div style={{ font: '800 88px/1 var(--font-sans)', letterSpacing: '-0.05em' }}>{n}<sup style={{ fontSize: 32, verticalAlign: 'top' }}>{s}</sup></div>
          <div style={{ fontWeight: 600, marginTop: 12 }}>{en}</div>
          <div className="t-ko" style={{ fontSize: 14, color: 'var(--fg2)' }}>{ko}</div>
        </div>
      ))}
    </div>
  </Wrap>
);

const RepoCard = ({ name, desc, tech, date, url, tags = [] }) => {
  const [h, setH] = React.useState(false);
  return (
    <a href={url} target="_blank" rel="noopener" onMouseEnter={() => setH(true)} onMouseLeave={() => setH(false)} style={{
      display: 'block', border: '1px solid', borderColor: h ? 'var(--gray-400)' : 'var(--border)', borderRadius: 6, padding: 20,
      background: 'var(--bg)', transition: 'border-color 120ms', cursor: 'pointer',
    }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 8, fontWeight: 600, fontSize: 16 }}>
        <Icon name="repo" /><span style={{ textDecoration: h ? 'underline' : 'none', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', minWidth: 0 }}>{name}</span>
        <span style={{ marginLeft: 'auto', fontSize: 12, fontWeight: 500, border: '1px solid var(--gray-300)', borderRadius: 99, padding: '0 8px', color: 'var(--fg2)' }}>Live</span>
      </div>
      <div className="t-ko" style={{ fontSize: 14, color: 'var(--fg2)', margin: '10px 0 14px' }}>{desc}</div>
      <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', marginBottom: 14 }}>
        {tags.map(t => <span key={t} style={{ fontSize: 12, fontWeight: 500, background: 'var(--bg-muted)', padding: '2px 10px', borderRadius: 99 }}>{t}</span>)}
      </div>
      <div style={{ display: 'flex', gap: 16, fontSize: 12, color: 'var(--fg2)', alignItems: 'center' }}>
        <span><span style={{ display: 'inline-block', width: 10, height: 10, borderRadius: 9, background: 'var(--fg1)', marginRight: 6 }} />{tech}</span>
        <span style={{ display: 'flex', gap: 4, alignItems: 'center' }}><Icon name="calendar" size={14} />{date}</span>
        <span style={{ display: 'flex', gap: 4, alignItems: 'center', minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}><Icon name="link" size={14} />{new URL(url).host}</span>
      </div>
    </a>
  );
};

// 업무(영상보안 · SI)용으로 직접 만들어 운영 중인 도구
const PROJECTS = [
  { name: 'CCTV 화각 시뮬레이터 3D', desc: '돔·불렛 카메라를 3D 공간에 놓고 화각·설치높이·틸트를 조절하면 감지 범위와 IDIS 센서 기준 초점거리가 실시간으로 계산됩니다.', tech: 'Three.js', date: '2026.08', url: 'https://fov3d.kimsangpil.com', tags: ['화각', 'Blender', 'glTF'], cat: 'tool' },
  { name: '제안서 시맨틱 검색', desc: '흩어져 있던 제안서 680여 개를 자연어 한 줄로 찾는 사내 검색 도구. 키워드가 아니라 의미로 검색합니다.', tech: 'LLM', date: '2026.06', url: 'https://sangfeel.kimsangpil.com', tags: ['제안서', 'AI'], cat: 'tool' },
  { name: 'IDIS-SMBT', desc: 'IDIS CCTV Linux SDK를 C++ MJPEG 브리지로 감싸고 Django + React를 얹은 리테일 방문객 분석 · 라이브 모니터링 플랫폼.', tech: 'C++ · Django', date: '2026.06', url: 'https://inex.idisman.co.kr/', tags: ['SDK', '리테일'], cat: 'tool' },
  { name: 'IDIS 제품 가격표', desc: '아이디스 전 제품의 에스원 기기코드·규격·단가를 정렬·필터로 조회하고 선택 리스트를 Excel로 내보내는 B2B 가격표.', tech: 'Django', date: '2026.05', url: 'https://s1.idisman.co.kr/', tags: ['에스원', 'B2B'], cat: 'tool' },
  { name: 'CCTV 화각 · 용량 계산기', desc: '초점거리와 거리별 촬영폭, PPM, 저장 용량과 대역폭을 계산합니다. 제안서 쓸 때 가장 자주 여는 도구.', tech: 'JavaScript', date: '2026.01', url: 'https://calc.idisman.co.kr/', tags: ['PPM', '대역폭'], cat: 'tool' },
  { name: '장비 단가표', desc: '제가 보려고 만들었다가 커진 장비 단가표.', tech: 'Django', date: '2026.02', url: 'https://pricelist.idisman.co.kr', tags: ['단가'], cat: 'tool' },
  { name: '제안자료 공유', desc: '제안자료를 작성하고 팀과 공유하는 사이트.', tech: 'Django', date: '2026.01', url: 'https://proposal.idisman.co.kr/', tags: ['제안서'], cat: 'tool' },
  { name: 'IDIS Tower 3D', desc: 'Blender로 직접 모델링해 웹에서 실시간으로 도는 3D. 204MB 원본을 17MB로 최적화했습니다.', tech: 'Blender', date: '2026.05', url: 'https://3dmodel.kimsangpil.com', tags: ['3D', 'Three.js'], cat: '3d' },
  { name: 'IDIS Smart Factory', desc: 'IDIS 공장을 브라우저에서 둘러보는 3D 디지털 트윈. 690MB 원본을 24MB로 줄였습니다.', tech: 'Three.js', date: '2026.06', url: 'https://3dmodel.kimsangpil.com/factory', tags: ['3D', '디지털 트윈'], cat: '3d' },
  { name: 'twinpeek', desc: 'IDIS Tower를 층·공간·시설 단위로 클릭 탐색하는 디지털 트윈 미리보기. Draco로 53MB → 15MB.', tech: 'Three.js', date: '2026.07', url: 'https://twinpeek.kimsangpil.com', tags: ['3D', '디지털 트윈'], cat: '3d' },
  { name: '3D 오브젝트를 웹으로', desc: '도면을 입체로 접는 첫 실험부터 움직이는 오브젝트, ISC West 2025 참관 기록까지 — 3D를 웹에 올린 실험 모음.', tech: 'Three.js', date: '2026.01', url: 'https://3d.idisman.co.kr/', tags: ['3D', 'ISC West'], cat: '3d' },
  { name: '프로젝트 공정관리시스템', desc: '프로젝트부터 현장, 공정까지 한 화면에서 관리합니다. 마일스톤을 엑셀 대신 웹으로.', tech: 'Django', date: '2026.03', url: 'https://smart.idisman.co.kr/', tags: ['SI', 'PM'], cat: 'field' },
  { name: '산업안전 TBM', desc: '중대재해 예방을 위한 현장 작업 전 안전점검(TBM) 사이트.', tech: 'Django', date: '2026.01', url: 'https://toolbox.idisman.co.kr/', tags: ['현장', '안전'], cat: 'field' },
  { name: '방문객 관리 시스템', desc: '방문객은 등록하고, 담당자는 승인합니다.', tech: 'Django', date: '2026.01', url: 'https://guest.kimsangpil.com/', tags: ['출입'], cat: 'field' },
  { name: 'AEGENT 가격 페이지', desc: '고객사 요청으로 만든, 쉽게 관리할 수 있는 가격 안내 페이지.', tech: 'HTML', date: '2026.01', url: 'https://aegent.idisman.co.kr/', tags: ['고객사'], cat: 'field' },
];

// 업무용 도구를 포트폴리오에 올린 날짜별 개수 (2026)
const PROJECT_LOG = { '2026-01-06': 3, '2026-01-12': 1, '2026-01-21': 1, '2026-01-29': 1, '2026-02-20': 1, '2026-03-16': 1,
  '2026-05-29': 1, '2026-05-30': 1, '2026-06-06': 1, '2026-06-11': 1, '2026-06-21': 1, '2026-07-22': 1, '2026-08-28': 1 };
const PROJECT_DATES = Object.entries(PROJECT_LOG).flatMap(([d, n]) => Array(n).fill(d));

const Contributions = () => {
  const end = new Date();
  const start = new Date(end); start.setDate(end.getDate() - end.getDay() - 7 * 51);
  const days = Array.from({ length: 7 * 52 }, (_, i) => { const d = new Date(start); d.setDate(start.getDate() + i); return d; });
  const key = d => `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
  const lv = d => { const n = d > end ? 0 : PROJECT_LOG[key(d)] || 0; return n === 0 ? 0 : n === 1 ? 2 : n < 4 ? 3 : 4; };
  return (
    <div style={{ border: '1px solid var(--border)', borderRadius: 6, padding: 20 }}>
      <div style={{ fontSize: 14, marginBottom: 12 }}><b>{PROJECT_DATES.length}</b> <span style={{ color: 'var(--fg2)' }}>work tools shipped · 업무용으로 만든 도구, 올린 날 기준</span></div>
      <div style={{ display: 'grid', gridTemplateRows: 'repeat(7,11px)', gridAutoFlow: 'column', gridAutoColumns: '1fr', gap: 3 }}>
        {days.map((d, i) => <i key={i} title={PROJECT_LOG[key(d)] ? `${key(d)} · ${PROJECT_LOG[key(d)]}개` : undefined} style={{ borderRadius: 2, minHeight: 11, background: `var(--level-${lv(d)})` }} />)}
      </div>
    </div>
  );
};

const Timeline = ({ items }) => (
  <div>
    {items.map((it, i) => (
      <div key={i} style={{ display: 'grid', gridTemplateColumns: '160px 40px 1fr', gap: 24, position: 'relative', paddingBottom: 40 }}>
        <div style={{ font: '500 14px var(--font-mono)', color: 'var(--fg2)', paddingTop: 8 }}>{it.year}</div>
        <div style={{ position: 'relative' }}>
          {i < items.length - 1 && <div style={{ position: 'absolute', left: 15, top: 32, bottom: -40, width: 2, background: 'var(--border)' }} />}
          <div style={{ width: 32, height: 32, borderRadius: 99, display: 'grid', placeItems: 'center', background: i === 0 ? 'var(--fg1)' : 'var(--bg-muted)', border: '1px solid', borderColor: i === 0 ? 'var(--fg1)' : 'var(--border)' }}>
            <Icon name={it.icon} invert={i === 0} />
          </div>
        </div>
        <div>
          <div style={{ font: '700 32px/1.15 var(--font-sans)', letterSpacing: '-0.025em' }}>{it.en}</div>
          <div className="t-ko-display" style={{ fontSize: 22, color: 'var(--fg2)', marginTop: 4 }}>{it.ko}</div>
          <p className="t-ko" style={{ fontSize: 15, color: 'var(--fg2)', margin: '12px 0 0', maxWidth: 620 }}>{it.desc}</p>
        </div>
      </div>
    ))}
  </div>
);

const Field = ({ label, ...p }) => {
  const [f, setF] = React.useState(false);
  const Tag = p.rows ? 'textarea' : 'input';
  return (
    <label style={{ display: 'grid', gap: 8 }}>
      <span style={{ fontWeight: 600, fontSize: 14 }}>{label}</span>
      <Tag {...p} onFocus={() => setF(true)} onBlur={() => setF(false)} style={{
        font: '16px var(--font-sans)', padding: p.rows ? 12 : '0 14px', height: p.rows ? 'auto' : 44, borderRadius: 6, resize: 'vertical',
        border: '1px solid', borderColor: f ? 'var(--fg1)' : 'var(--gray-300)', outline: 'none',
        boxShadow: f ? '0 0 0 3px rgba(0,0,0,.12)' : 'none', background: f ? 'var(--bg)' : 'var(--bg-subtle)',
      }} />
    </label>
  );
};

Object.assign(window, { Wrap, Eyebrow, SectionHead, Hero, Stats, RepoCard, PROJECTS, PROJECT_DATES, Contributions, Timeline, Field });
