/* ============================================================
   Builder wizard — steps 4-8
   ============================================================ */

/* ---------------- STEP 4: ABILITY SCORES ---------------- */
function AbilitiesStep({ char, patch }){
  const method = char.abilityMethod;
  const base = char.baseScores;
  const bg = DND.resolvedBg(char);
  const final = DND.finalScores(char);

  const setMethod = (m)=>{
    let next = { abilityMethod:m };
    if (m==="array") next.baseScores = { str:8,dex:8,con:8,int:8,wis:8,cha:8 };
    if (m==="pointbuy") next.baseScores = { str:8,dex:8,con:8,int:8,wis:8,cha:8 };
    if (m==="roll") { next.baseScores = { str:8,dex:8,con:8,int:8,wis:8,cha:8 }; next.rolledPool=null; }
    patch(next);
  };

  /* ----- point buy ----- */
  const spent = DND.pointBuySpent(base);
  const remaining = DND.POINT_BUY_BUDGET - spent;
  const stepPB = (k, dir)=>{
    const v = base[k] + dir;
    if (v < DND.POINT_BUY_MIN || v > DND.POINT_BUY_MAX) return;
    const trial = {...base, [k]:v};
    if (DND.pointBuySpent(trial) > DND.POINT_BUY_BUDGET) return;
    patch({ baseScores: trial });
  };

  /* ----- array & roll: assignment ----- */
  const pool = method==="array" ? DND.STANDARD_ARRAY : (char.rolledPool || []);
  const assignMap = char.assignMap || {}; // ability -> pool index
  const usedIdx = new Set(Object.values(assignMap).filter(v=>v!=null && v!==""));
  const assign = (k, idxStr)=>{
    const idx = idxStr===""? null : Number(idxStr);
    const nextMap = {...assignMap};
    // free any ability currently holding this idx
    Object.keys(nextMap).forEach(a=>{ if(nextMap[a]===idx) nextMap[a]=null; });
    nextMap[k]=idx;
    const nextScores = {...base};
    ABK.forEach(a=> nextScores[a] = (nextMap[a]!=null && pool[nextMap[a]]!=null) ? pool[nextMap[a]] : 8);
    patch({ assignMap:nextMap, baseScores:nextScores });
  };
  const doRoll = ()=>{
    const p = [0,0,0,0,0,0].map(()=>roll4d6());
    patch({ rolledPool:p, assignMap:{}, baseScores:{str:8,dex:8,con:8,int:8,wis:8,cha:8} });
  };

  /* ----- background ASI ----- */
  const asiMode = char.asiMode; // "2-1" | "1-1-1"
  const asi = char.asi;
  const bgAbils = bg ? bg.abilities : [];
  const setAsiMode = (mode)=>{
    let next = {str:0,dex:0,con:0,int:0,wis:0,cha:0};
    if (mode==="1-1-1") bgAbils.forEach(a=>next[a]=1);
    patch({ asiMode:mode, asi:next, asiPrimary:null });
  };
  const setPrimary = (a)=>{ // +2 target; the +1 goes to a chosen secondary
    patch({ asiPrimary:a, asiSecondary:null, asi:{str:0,dex:0,con:0,int:0,wis:0,cha:0, [a]:2} });
  };
  const setSecondary = (a)=>{
    const next = {str:0,dex:0,con:0,int:0,wis:0,cha:0};
    if (char.asiPrimary) next[char.asiPrimary]=2;
    next[a]=(next[a]||0)+1;
    patch({ asiSecondary:a, asi:next });
  };

  return (
    <div>
      <StepHeader eyebrow="Step 4 · Ability Scores" title="Set your ability scores"
        sub="The six abilities underpin everything you roll. Pick a generation method, then apply your background's increases." />

      <div style={{display:"flex",gap:14,alignItems:"center",flexWrap:"wrap",marginTop:22}}>
        <div className="seg">
          {[["pointbuy","Point Buy"],["array","Standard Array"],["roll","Roll 4d6"]].map(([k,l])=>(
            <button key={k} className={method===k?"on":""} onClick={()=>setMethod(k)}>{l}</button>
          ))}
        </div>
        {method==="pointbuy" && <Budget label="Points remaining" value={remaining} total={DND.POINT_BUY_BUDGET} over={remaining<0} />}
        {method==="array" && <span className="hint">Assign 15, 14, 13, 12, 10, 8 — each once.</span>}
        {method==="roll" && <button className="btn" onClick={doRoll}><Ic.dice/> {char.rolledPool?"Re-roll":"Roll"} 4d6 ×6</button>}
      </div>

      {method==="roll" && char.rolledPool && (
        <div className="chip-row" style={{marginTop:14}}>
          {char.rolledPool.map((v,i)=>(
            <span key={i} className={"tag"+(usedIdx.has(i)?"":" acc")} style={{fontFamily:"var(--mono)",fontSize:13}}>{v}{usedIdx.has(i)?" ·used":""}</span>
          ))}
        </div>
      )}
      {method==="roll" && !char.rolledPool && (
        <div style={{marginTop:16}}><Callout amber>Click <b>Roll 4d6 ×6</b> to generate a pool (4d6, drop the lowest). Then assign each result to an ability below.</Callout></div>
      )}

      <SectionCap>Abilities</SectionCap>
      <div className="abil-grid">
        {DND.ABILITIES.map(a=>{
          const k=a.key;
          const inc = asi[k]||0;
          const fmod = DND.mod(final[k]);
          return (
            <div className="abil-card" key={k}>
              <div className="top">
                <span className="lbl">{a.name}</span>
                <span className="modbadge mono">{DND.fmt(fmod)}</span>
              </div>
              <div className="score mono">{final[k]}{inc>0 && <small>({base[k]}+{inc})</small>}</div>

              {method==="pointbuy" && (
                <div className="ctrl">
                  <button onClick={()=>stepPB(k,-1)} disabled={base[k]<=DND.POINT_BUY_MIN}>−</button>
                  <span className="mono" style={{minWidth:24,textAlign:"center",fontWeight:600}}>{base[k]}</span>
                  <button onClick={()=>stepPB(k,1)} disabled={base[k]>=DND.POINT_BUY_MAX || DND.pointBuySpent({...base,[k]:base[k]+1})>DND.POINT_BUY_BUDGET}>+</button>
                </div>
              )}
              {(method==="array" || method==="roll") && (
                <select value={assignMap[k]==null?"":assignMap[k]} onChange={e=>assign(k,e.target.value)}>
                  <option value="">— assign —</option>
                  {pool.map((v,i)=>(
                    <option key={i} value={i} disabled={usedIdx.has(i) && assignMap[k]!==i}>{v}</option>
                  ))}
                </select>
              )}
              {inc>0 && <div className="asitag">+{inc} from background</div>}
            </div>
          );
        })}
      </div>

      {/* Background ASI allocation */}
      {bg && (
        <div>
          <SectionCap>Background Increase — {bg.name}</SectionCap>
          <Callout>Increase one of <b>{bgAbils.map(abilName).join(", ")}</b> by 2 and another by 1 — or increase all three by 1. No score may exceed 20.</Callout>
          <div style={{display:"flex",gap:10,marginTop:14,flexWrap:"wrap"}}>
            <div className="seg">
              <button className={asiMode==="2-1"?"on":""} onClick={()=>setAsiMode("2-1")}>+2 / +1</button>
              <button className={asiMode==="1-1-1"?"on":""} onClick={()=>setAsiMode("1-1-1")}>+1 / +1 / +1</button>
            </div>
          </div>
          {asiMode==="2-1" && (
            <div style={{marginTop:14,display:"grid",gap:14,gridTemplateColumns:"1fr 1fr",maxWidth:520}}>
              <div>
                <div className="hint" style={{marginBottom:7}}>+2 to</div>
                <div className="chip-row">{bgAbils.map(a=><Chip key={a} label={abilName(a)} on={char.asiPrimary===a} onClick={()=>setPrimary(a)} />)}</div>
              </div>
              <div>
                <div className="hint" style={{marginBottom:7}}>+1 to</div>
                <div className="chip-row">{bgAbils.map(a=><Chip key={a} label={abilName(a)} disabled={char.asiPrimary===a} on={char.asiSecondary===a} onClick={()=>setSecondary(a)} />)}</div>
              </div>
            </div>
          )}
        </div>
      )}

      {/* Level-up Improvements & Feats */}
      {DND.asiSlots(char)>0 && (()=>{
        const milestones = DND.asiLevelsFor(char.classKey).filter(l=>l<=char.level);
        const lc = char.levelChoices || {};
        return (
          <div>
            <SectionCap>Level-up: Improvements &amp; Feats</SectionCap>
            <Callout>At levels {milestones.join(", ")} you gain an Ability Score Improvement. For each, raise your ability scores <b>or take a Feat</b> instead.</Callout>
            <div style={{display:"grid",gap:12,marginTop:14}}>
              {milestones.map(lvl=>(
                <MilestoneCard key={lvl} lvl={lvl} char={char} choice={lc[lvl]}
                  onChange={(v)=>patch({ levelChoices:{...lc, [lvl]:v} })} />
              ))}
            </div>
          </div>
        );
      })()}
    </div>
  );
}

/* One ASI/Feat milestone */
function MilestoneCard({ lvl, choice, onChange, char }){
  const c = choice || { type:null };
  const isEpicBoon = lvl === 19;
  const setType = (t)=>
    t==="asi"  ? onChange({ type:"asi",  mode:"two", a:null, b:null }) :
    t==="boon" ? onChange({ type:"boon", boon:null,  abil:null }) :
                 onChange({ type:"feat", feat:null,  abil:null });
  const feats = DND.FEATS_GENERAL.filter(f=>f.ability!=="asi");
  const gf = c.feat ? DND.generalFeat(c.feat) : null;
  const ef = c.boon ? DND.EPIC_BOON_FEATS.find(f=>f.name===c.boon) : null;
  return (
    <div className="ms-card">
      <div className="ms-head">
        <span className="ms-lv mono">Lv {lvl}</span>
        <span className="ms-title">{isEpicBoon ? "Epic Boon" : "Ability Score Improvement or Feat"}</span>
        <div className="seg sm" style={{marginLeft:"auto"}}>
          {isEpicBoon ? (
            <button className={c.type==="boon"?"on":""} onClick={()=>setType("boon")}>Epic Boon</button>
          ) : (<React.Fragment>
            <button className={c.type==="asi"?"on":""} onClick={()=>setType("asi")}>Ability Scores</button>
            <button className={c.type==="feat"?"on":""} onClick={()=>setType("feat")}>Feat</button>
          </React.Fragment>)}
        </div>
      </div>
      {c.type==="asi" && (
        <div className="ms-body">
          <div className="seg sm">
            <button className={c.mode==="two"?"on":""} onClick={()=>onChange({...c, mode:"two", b:null})}>+2 to one</button>
            <button className={c.mode==="split"?"on":""} onClick={()=>onChange({...c, mode:"split"})}>+1 / +1</button>
          </div>
          {c.mode==="two" && (
            <div style={{marginTop:11}}>
              <div className="hint" style={{marginBottom:7}}>+2 to</div>
              <div className="chip-row">{DND.ABILITIES.map(a=><Chip key={a.key} label={a.name} on={c.a===a.key} onClick={()=>onChange({...c,a:a.key})}/>)}</div>
            </div>
          )}
          {c.mode==="split" && (
            <div style={{marginTop:11,display:"grid",gridTemplateColumns:"1fr 1fr",gap:12}} className="loadout-grid">
              <div><div className="hint" style={{marginBottom:7}}>+1 to</div><div className="chip-row">{DND.ABILITIES.map(a=><Chip key={a.key} label={a.name} on={c.a===a.key} disabled={c.b===a.key} onClick={()=>onChange({...c,a:a.key})}/>)}</div></div>
              <div><div className="hint" style={{marginBottom:7}}>+1 to</div><div className="chip-row">{DND.ABILITIES.map(a=><Chip key={a.key} label={a.name} on={c.b===a.key} disabled={c.a===a.key} onClick={()=>onChange({...c,b:a.key})}/>)}</div></div>
            </div>
          )}
        </div>
      )}
      {c.type==="feat" && (
        <div className="ms-body">
          <div className="feat-pick">
            {feats.map(f=>{
              const on = c.feat===f.name;
              return (
                <button key={f.name} className={"feat-opt"+(on?" sel":"")}
                  onClick={()=>onChange({ type:"feat", feat:f.name, abil: on?c.abil:null })}>
                  <div className="fo-top">
                    <span className="fo-name">{f.name}</span>
                    {Array.isArray(f.ability) && <span className="fo-asi">+1 {f.ability.map(a=>a.toUpperCase()).join("/")}</span>}
                    {on && <span className="fo-check"><Ic.check/></span>}
                  </div>
                  <div className="fo-text">{f.text}</div>
                </button>
              );
            })}
          </div>
          {gf && Array.isArray(gf.ability) && (
            <div style={{marginTop:14}}>
              <div className="hint" style={{marginBottom:7}}>This feat grants +1 to an ability — choose which:</div>
              <div className="chip-row">{gf.ability.map(ak=><Chip key={ak} label={abilName(ak)} on={c.abil===ak} onClick={()=>onChange({...c, abil:ak})}/>)}</div>
            </div>
          )}
          {/* Elemental Adept — damage type */}
          {c.feat==="Elemental Adept" && (
            <div style={{marginTop:14}}>
              <div className="hint" style={{marginBottom:7}}>Choose a damage type:</div>
              <div className="chip-row">
                {["Acid","Cold","Fire","Lightning","Poison","Thunder"].map(dt=>(
                  <Chip key={dt} label={dt} on={c.damageType===dt} onClick={()=>onChange({...c,damageType:dt})} />
                ))}
              </div>
            </div>
          )}
          {/* Fey-Touched — Divination or Enchantment level-1 spell */}
          {c.feat==="Fey-Touched" && (
            <div style={{marginTop:14}}>
              <div className="hint" style={{marginBottom:7}}>Choose a Divination or Enchantment level-1 spell:</div>
              <div className="chip-row">
                {["Bless","Charm Person","Command","Detect Evil and Good","Detect Magic","Detect Poison and Disease","Heroism","Identify","Sleep","Speak with Animals","Tasha's Hideous Laughter"].map(sp=>(
                  <Chip key={sp} label={sp} on={c.spell===sp} onClick={()=>onChange({...c,spell:c.spell===sp?null:sp})} />
                ))}
              </div>
            </div>
          )}
          {/* Shadow-Touched — Illusion or Necromancy level-1 spell */}
          {c.feat==="Shadow-Touched" && (
            <div style={{marginTop:14}}>
              <div className="hint" style={{marginBottom:7}}>Choose an Illusion or Necromancy level-1 spell:</div>
              <div className="chip-row">
                {["Cause Fear","Color Spray","Disguise Self","False Life","Inflict Wounds","Ray of Sickness","Silent Image"].map(sp=>(
                  <Chip key={sp} label={sp} on={c.spell===sp} onClick={()=>onChange({...c,spell:c.spell===sp?null:sp})} />
                ))}
              </div>
            </div>
          )}
          {/* Skill Expert — new proficiency + expertise */}
          {c.feat==="Skill Expert" && (()=>{
            const existingProfs = char ? Array.from(DND.skillProfs(char)) : [];
            const afterProfs = c.skillProf ? [...new Set([...existingProfs, c.skillProf])] : existingProfs;
            return (
              <div style={{marginTop:14}}>
                <div className="hint" style={{marginBottom:7}}>New skill proficiency — choose one:</div>
                <div className="chip-row">
                  {DND.SKILLS.map(s=>(
                    <Chip key={s.key} label={s.name} on={c.skillProf===s.key}
                      disabled={existingProfs.includes(s.key)}
                      onClick={()=>onChange({...c, skillProf:c.skillProf===s.key?null:s.key,
                        expertiseProf: c.expertiseProf===s.key ? null : c.expertiseProf})} />
                  ))}
                </div>
                {afterProfs.length>0 && (
                  <div style={{marginTop:10}}>
                    <div className="hint" style={{marginBottom:7}}>Expertise — choose one of your proficient skills:</div>
                    <div className="chip-row">
                      {afterProfs.map(k=>(
                        <Chip key={k} label={DND.skillName(k)} on={c.expertiseProf===k}
                          onClick={()=>onChange({...c, expertiseProf:c.expertiseProf===k?null:k})} />
                      ))}
                    </div>
                  </div>
                )}
              </div>
            );
          })()}
        </div>
      )}
      {c.type==="boon" && (
        <div className="ms-body">
          <div className="feat-pick">
            {DND.EPIC_BOON_FEATS.map(f=>{
              const on = c.boon===f.name;
              return (
                <button key={f.name} className={"feat-opt"+(on?" sel":"")}
                  onClick={()=>onChange({ type:"boon", boon:f.name, abil: on?c.abil:null })}>
                  <div className="fo-top">
                    <span className="fo-name">{f.name}</span>
                    {on && <span className="fo-check"><Ic.check/></span>}
                  </div>
                  <div className="fo-text">{f.text}</div>
                </button>
              );
            })}
          </div>
          {ef && (
            <div style={{marginTop:14}}>
              <div className="hint" style={{marginBottom:7}}>This boon grants +1 to an ability score (max 30) — choose which:</div>
              <div className="chip-row">{ef.ability.map(ak=><Chip key={ak} label={abilName(ak)} on={c.abil===ak} onClick={()=>onChange({...c, abil:ak})}/>)}</div>
            </div>
          )}
        </div>
      )}
    </div>
  );
}

/* ---------------- STEP 5: SKILLS ---------------- */
function SkillsStep({ char, patch }){
  const cls = DND.klass(char.classKey);
  const bg = DND.resolvedBg(char);
  const fromBg = new Set(bg?bg.skills:[]);
  const fromSpecies = new Set();
  if (char.elfKeenSense) fromSpecies.add(char.elfKeenSense);
  if (char.humanSkill) fromSpecies.add(char.humanSkill);
  const fromSkilled = new Set(char.bonusSkills||[]);
  const fromCustom = new Set(
    char.speciesKey==="custom" && char.customSpecies
      ? (char.customSpecies.proficiencies||[]).filter(k=>DND.SKILLS.some(s=>s.key===k))
      : []
  );
  const fromSkillExpert = new Set(
    Object.values(char.levelChoices||{})
      .filter(c=>c&&c.type==="feat"&&c.feat==="Skill Expert"&&c.skillProf)
      .map(c=>c.skillProf)
  );
  const grantedElsewhere = (k) =>
    fromBg.has(k)||fromSpecies.has(k)||fromSkilled.has(k)||fromCustom.has(k)||fromSkillExpert.has(k);

  const classList = cls ? (cls.skillList==="any" ? DND.SKILLS.map(s=>s.key) : cls.skillList) : [];
  const chosen = char.classSkills || [];
  const need = cls ? cls.skillCount : 0;

  const toggle = (k)=>{
    if (grantedElsewhere(k)) return; // already granted from another source
    let next = chosen.includes(k) ? chosen.filter(x=>x!==k) : (chosen.length<need ? [...chosen,k] : chosen);
    patch({ classSkills: next });
  };

  // rogue / bard expertise (rogue gets 2 at L1)
  const expertiseN = (char.classKey==="rogue" || char.classKey==="bard") ? 2 : 0;
  const profForExpertise = Array.from(new Set([...chosen, ...fromBg, ...fromSpecies, ...fromSkilled, ...fromCustom, ...fromSkillExpert]));
  const expertise = char.expertise || [];
  const toggleExp = (k)=>{
    let next = expertise.includes(k)? expertise.filter(x=>x!==k) : (expertise.length<expertiseN?[...expertise,k]:expertise);
    patch({ expertise: next });
  };

  return (
    <div>
      <StepHeader eyebrow="Step 5 · Skills" title="Choose your skills"
        sub={`Your background and species already grant some proficiencies. Pick ${need} more from your ${cls?cls.name:"class"} list.`} />

      <SectionCap>{cls?cls.name:"Class"} skills — choose {need} <span style={{color:chosen.length===need?"var(--good)":"var(--accent)",marginLeft:8}}>({chosen.length}/{need})</span></SectionCap>
      <div className="chip-row">
        {classList.map(k=>{
          const granted = grantedElsewhere(k);
          const on = chosen.includes(k)||granted;
          const full = chosen.length>=need && !chosen.includes(k);
          return <Chip key={k} label={DND.skillName(k)} on={on} dot={on}
            disabled={granted || (full && !granted)}
            onClick={()=>toggle(k)} />;
        })}
      </div>

      <SectionCap>Already granted</SectionCap>
      <div className="chip-row">
        {Array.from(fromBg).map(k=><Chip key={"b"+k} label={`${DND.skillName(k)} · ${bg.name}`} on dot />)}
        {Array.from(fromSpecies).map(k=><Chip key={"sp"+k} label={`${DND.skillName(k)} · species`} on dot />)}
        {Array.from(fromSkilled).map(k=><Chip key={"sk"+k} label={`${DND.skillName(k)} · Skilled`} on dot />)}
        {Array.from(fromCustom).map(k=><Chip key={"cs"+k} label={`${DND.skillName(k)} · Custom Lineage`} on dot />)}
        {Array.from(fromSkillExpert).map(k=><Chip key={"se"+k} label={`${DND.skillName(k)} · Skill Expert`} on dot />)}
        {fromBg.size===0&&fromSpecies.size===0&&fromSkilled.size===0&&fromCustom.size===0&&fromSkillExpert.size===0 && <span className="hint">None yet.</span>}
      </div>

      {expertiseN>0 && (
        <div>
          <SectionCap>Expertise — choose {expertiseN} <span style={{color:expertise.length===expertiseN?"var(--good)":"var(--accent)",marginLeft:8}}>({expertise.length}/{expertiseN})</span></SectionCap>
          <Callout>{char.classKey==="bard"?"Bards":"Rogues"} double their Proficiency Bonus on two chosen proficient skills.</Callout>
          <div className="chip-row" style={{marginTop:12}}>
            {profForExpertise.length===0 && <span className="hint">Pick your class skills first.</span>}
            {profForExpertise.map(k=>{
              const full = expertise.length>=expertiseN && !expertise.includes(k);
              return <Chip key={k} label={DND.skillName(k)} on={expertise.includes(k)} disabled={full} onClick={()=>toggleExp(k)} />;
            })}
          </div>
        </div>
      )}
    </div>
  );
}

Object.assign(window, { AbilitiesStep, SkillsStep, MilestoneCard });
