// Character view — gold, carved materials, spells
const CharacterView = ({ characterId, user, setNav }) => {
  const [ch, setCh] = React.useState(null);
  const [loading, setLoading] = React.useState(true);
  const [loadError, setLoadError] = React.useState(null);
  // Sheet is the default landing tab — it's what players will look at most.
  const [tab, setTab] = React.useState('sheet');

  // Partial-PATCH helper used by the sheet tab. Optimistic local update so
  // inputs feel snappy, then fire-and-forget the API call. On failure we'd
  // ideally rebase from the server, but for now we just log and keep the
  // local change — the user will notice if a save genuinely fails.
  const patchCh = React.useCallback(async (patch) => {
    if (!ch) return;
    setCh(prev => ({ ...prev, ...patch }));
    try { await api.characters.update(ch.id, patch); }
    catch (err) { console.error('[CharacterView] save failed:', err, patch); }
  }, [ch?.id]);

  // Hard-refresh from the server. Used by sub-rows (materials) where an add
  // or delete returns no payload — we need to refetch to see the canonical
  // list with its new id + index ordering.
  const refreshCh = React.useCallback(async () => {
    if (!ch) return;
    try {
      const fresh = await api.characters.get(ch.id);
      setCh(api.augmentCharacter(fresh));
    } catch (err) { console.error('[CharacterView] refresh failed:', err); }
  }, [ch?.id]);

  React.useEffect(() => {
    let cancelled = false;
    setLoading(true); setLoadError(null);
    api.characters.get(characterId)
      .then(c => { if (!cancelled) { setCh(api.augmentCharacter(c)); setLoading(false); } })
      .catch(err => { if (!cancelled) { setLoadError(err.status === 404 ? 'Character not found.' : (err.message || 'Failed to load character.')); setLoading(false); } });
    return () => { cancelled = true; };
  }, [characterId]);

  // Load the campaigns this user can see — needed for the "Join campaign"
  // picker when the character is free-floating.
  const [campaigns, setCampaigns] = React.useState([]);
  React.useEffect(() => {
    api.campaigns.list().then(list => setCampaigns(list || []))
      .catch(err => console.error('[CharacterView] campaigns load failed:', err));
  }, []);
  const [joinPickerOpen, setJoinPickerOpen] = React.useState(false);
  const isOwner = ch && user.id === ch.playerId;

  if (loading)   return <div style={{color:'#9a9793',padding:40}}>Loading character…</div>;
  if (loadError) return <div style={{color:'#9a9793',padding:40}}>{loadError}</div>;
  if (!ch)       return <div style={{color:'#9a9793',padding:40}}>Character not found.</div>;
  // Free-floating characters have no campaign reference.
  const attached = !!ch.campaignId;
  const campaign = attached ? { id: ch.campaignId, name: ch.campaignName } : null;

  const joinCampaign = async (campaignId) => {
    if (!campaignId) return;
    try {
      await api.characters.joinCampaign(ch.id, campaignId);
      await refreshCh();
      setJoinPickerOpen(false);
    } catch (err) {
      console.error('[CharacterView] join failed:', err);
      window.dialog.alert((err.body && err.body.message) || err.message || 'Could not join campaign.', { title:'Join failed' });
    }
  };
  const leaveCampaign = async () => {
    const ok = await window.dialog.confirm({
      title: 'Leave campaign?',
      message: `Detach ${ch.name} from "${ch.campaignName}"? The character keeps all its data and can re-join later. The DM keeps any campaign-side references that point at it.`,
      confirmLabel: 'Leave',
    });
    if (!ok) return;
    try {
      await api.characters.leaveCampaign(ch.id);
      await refreshCh();
    } catch (err) {
      console.error('[CharacterView] leave failed:', err);
      window.dialog.alert((err.body && err.body.message) || err.message || 'Could not leave campaign.', { title:'Error' });
    }
  };

  const spellLevelColors = {0:'#6b6966',1:'#1e6b3c',2:'#1a5c7a',3:'#b45309',4:'#7c3aed',5:'#c53030',6:'#991b1b',7:'#6b1a1a',8:'#4a0a0a',9:'#c9a227'};

  return (
    <div style={charStyles.page}>
      {/* Hero */}
      <div style={charStyles.hero}>
        <button style={charStyles.backBtn} onClick={() => attached
          ? setNav({ view: 'campaign', campaignId: ch.campaignId, tab: 'overview' })
          : setNav({ view: 'dashboard' })}>
          ← {attached ? campaign.name : 'Dashboard'}
        </button>
        <div style={charStyles.heroMain}>
          <div style={charStyles.heroAvatar}>{ch.name.split(' ').map(w=>w[0]).join('')}</div>
          <div style={{ flex:1 }}>
            <h1 style={charStyles.heroName}>{ch.name}</h1>
            <div style={charStyles.heroMeta}>{ch.race || '—'} · {ch.class || '—'}{ch.subclass ? ` (${ch.subclass})` : ''} · Level {ch.level}</div>
            <div style={{fontSize:12, color:'#6b6966', marginTop:2, display:'flex', alignItems:'center', gap:8, flexWrap:'wrap'}}>
              {attached ? (
                <>
                  <span>Campaign: <span style={{color:'#c9a227'}}>{campaign.name}</span></span>
                  {isOwner && (
                    <button onClick={leaveCampaign}
                      title="Detach this character from the campaign. Reversible."
                      style={{ background:'transparent', border:'1px solid rgba(248,113,113,0.25)', color:'#f87171', borderRadius:5, padding:'2px 8px', cursor:'pointer', fontSize:11, fontFamily:"'Nunito',sans-serif" }}>
                      Leave campaign
                    </button>
                  )}
                </>
              ) : (
                <>
                  <span style={{ color:'#a78bfa', fontWeight:700 }}>Unattached</span>
                  <span>— this character isn't in a campaign yet.</span>
                  {isOwner && !joinPickerOpen && (
                    <button onClick={() => setJoinPickerOpen(true)}
                      style={{ background:'rgba(167,139,250,0.15)', border:'1px solid #a78bfa55', color:'#a78bfa', borderRadius:5, padding:'2px 10px', cursor:'pointer', fontSize:11, fontFamily:"'Nunito',sans-serif", fontWeight:700 }}>
                      Join a campaign
                    </button>
                  )}
                  {isOwner && joinPickerOpen && (
                    <>
                      <select autoFocus defaultValue="" onChange={e => e.target.value && joinCampaign(e.target.value)}
                        style={{ background:'#16161b', border:'1px solid #2a2a32', color:'#e8e6e3', borderRadius:5, padding:'3px 6px', fontSize:12, fontFamily:"'Nunito',sans-serif" }}>
                        <option value="">— Pick a campaign —</option>
                        {(campaigns || []).filter(c => c.status !== 'archived').map(c => <option key={c.id} value={c.id}>{c.name}</option>)}
                      </select>
                      <button onClick={() => setJoinPickerOpen(false)}
                        style={{ background:'transparent', border:'none', color:'#6b6966', fontSize:11, cursor:'pointer' }}>Cancel</button>
                    </>
                  )}
                </>
              )}
            </div>
          </div>
        </div>
        {/* Wealth summary */}
        <div style={charStyles.wealthBar}>
          <div style={charStyles.wealthChip}>
            <span style={charStyles.gpLabel}>GP</span>
            <span style={charStyles.gpValue}>{ch.gold}</span>
          </div>
          <div style={charStyles.wealthChip}>
            <span style={{...charStyles.gpLabel, color:'#9a9793'}}>SP</span>
            <span style={charStyles.gpValue}>{ch.silver}</span>
          </div>
          <div style={charStyles.wealthChip}>
            <span style={{...charStyles.gpLabel, color:'#b45309'}}>CP</span>
            <span style={charStyles.gpValue}>{ch.copper}</span>
          </div>
        </div>
      </div>

      {/* Tabs. Wealth + Carved Materials used to be separate; they're now
          sections inside Sheet, so the tab strip is shorter. */}
      <div style={charStyles.tabs}>
        {['sheet','spells','specialization'].map(t => (
          <button key={t} style={{...charStyles.tab, ...(tab===t ? charStyles.tabActive : {})}} onClick={() => setTab(t)}>
            {t === 'sheet' ? 'Sheet' : t === 'spells' ? 'Spellbook & Scrolls' : 'Specialization'}
          </button>
        ))}
      </div>

      <div style={charStyles.content}>
        {tab === 'sheet' && (
          // Editable for the owning user, DM, or admin. The backend re-checks
          // on every PATCH — this just gates the UI affordances.
          <CharacterSheetTab
            ch={ch}
            editable={user.id === ch.playerId || user.isAdmin}
            onPatch={patchCh}
            onRefresh={refreshCh}
          />
        )}

        {tab === 'spells' && (
          <div style={{maxWidth:800}}>
            {ch.spellbook.length === 0 && ch.scrollsCarried.length === 0 ? (
              <div style={{color:'#6b6966', fontSize:14, textAlign:'center', padding:40}}>This character carries no spells or scrolls.</div>
            ) : (
              <>
                {ch.spellbook.length > 0 && (
                  <div style={{...charStyles.card, marginBottom:20}}>
                    <div style={{display:'flex', justifyContent:'space-between', alignItems:'center', marginBottom:16}}>
                      <div style={charStyles.cardTitle}>Spellbook — {ch.spellbook.length} spells</div>
                      <button style={charStyles.addBtn}>+ Add Spell</button>
                    </div>
                    <div style={{display:'flex', flexDirection:'column', gap:8}}>
                      {ch.spellbook.map((sp,i) => (
                        <div key={i} style={{...charStyles.spellRow, opacity: sp.prepared ? 1 : 0.55}}>
                          <div style={{...charStyles.spellLevel, background: (spellLevelColors[sp.level]||'#6b6966')+'22', color: spellLevelColors[sp.level]||'#6b6966'}}>
                            {sp.level === 0 ? 'C' : sp.level}
                          </div>
                          <div style={{flex:1}}>
                            <div style={{fontSize:14, fontWeight:700, color:'#e8e6e3'}}>{sp.name}</div>
                            <div style={{fontSize:11, color:'#6b6966', textTransform:'capitalize'}}>{sp.source}</div>
                          </div>
                          <div style={{display:'flex', alignItems:'center', gap:8}}>
                            {sp.prepared && <span style={charStyles.preparedBadge}>● Prepared</span>}
                            {!sp.prepared && <span style={{fontSize:11, color:'#4a4a52'}}>Unprepared</span>}
                          </div>
                        </div>
                      ))}
                    </div>
                  </div>
                )}
                {ch.scrollsCarried.length > 0 && (
                  <div style={charStyles.card}>
                    <div style={{display:'flex', justifyContent:'space-between', alignItems:'center', marginBottom:16}}>
                      <div style={charStyles.cardTitle}>Scrolls Carried — {ch.scrollsCarried.length}</div>
                      <button style={charStyles.addBtn}>+ Add Scroll</button>
                    </div>
                    <div style={{display:'flex', flexDirection:'column', gap:8}}>
                      {ch.scrollsCarried.map((sc,i) => (
                        <div key={i} style={charStyles.spellRow}>
                          <div style={{...charStyles.spellLevel, background:'rgba(201,162,39,0.12)', color:'#c9a227'}}>📜</div>
                          <div style={{flex:1}}>
                            <div style={{fontSize:14, fontWeight:700, color:'#e8e6e3'}}>{sc.name}</div>
                            <div style={{fontSize:11, color:'#6b6966', textTransform:'capitalize'}}>{sc.source}</div>
                          </div>
                          <div style={{fontSize:12, color:'#b45309', fontWeight:700}}>
                            Level {sc.level}
                          </div>
                        </div>
                      ))}
                    </div>
                  </div>
                )}
              </>
            )}
          </div>
        )}
        {tab === 'specialization' && <SpecializationTab ch={ch} />}
      </div>
    </div>
  );
};

const SPEC_ALL = [
  { name:'Blacksmith', tools:"Smith's tools", skills:'Str, Dex, Con' },
  { name:'Leatherworker', tools:"Leatherworker's tools", skills:'Str, Dex, Con' },
  { name:'Woodworker', tools:"Carpenter's tools", skills:'Str, Dex, Con' },
  { name:'Stonemason', tools:"Mason's tools", skills:'Str, Dex, Con' },
  { name:'Alchemist', tools:"Alchemist's tools", skills:'Arcana, Medicine' },
  { name:'Herbalist', tools:"Herbalist's tools", skills:'Nature, Medicine' },
  { name:'Beastmaster', tools:'Animal Handling', skills:'Animal Handling, Insight' },
  { name:'Enchanter', tools:"Tinkerer's tools", skills:'Sleight of Hand, Arcana' },
  { name:'Butcher', tools:"Cook's tools", skills:'Animal Handling, Nature' },
  { name:'Cook', tools:"Cook's tools", skills:'Survival, Nature' },
  { name:'Scout', tools:"Cartographer's tools", skills:'Investigation, Stealth' },
  { name:'Recruiter', tools:"Calligrapher's tools", skills:'Performance, Persuasion' },
  { name:'Receptionist', tools:"Calligrapher's tools", skills:'Insight, Investigation' },
  { name:'Trader', tools:"Calligrapher's tools", skills:'Insight, Persuasion' },
  { name:'Fisher', tools:'Survival', skills:'Survival, Stealth' },
];
const SPEC_LEVELS_CH = ['Apprentice','Journeyman','Master','Grandmaster'];
const SPEC_LVL_COLOR_CH = { Apprentice:'#6b6966', Journeyman:'#1e6b3c', Master:'#1a5c7a', Grandmaster:'#c9a227' };

const SpecializationTab = ({ ch }) => {
  // Load this character's campaign guild and find their membership row.
  const [guild, setGuild] = React.useState(null);
  React.useEffect(() => {
    let cancelled = false;
    api.guilds.get(ch.campaignId)
      .then(g => { if (!cancelled) setGuild(g); })
      .catch(err => { if (err.status !== 404) console.error('[SpecializationTab] guild load failed:', err); });
    return () => { cancelled = true; };
  }, [ch.campaignId]);
  const guildMember = guild?.members?.find(m => m.playerId === ch.playerId);
  const [spec, setSpec] = React.useState('');
  const [level, setLevel] = React.useState('Apprentice');
  React.useEffect(() => {
    if (guildMember) { setSpec(guildMember.specialization || ''); setLevel(guildMember.specLevel || 'Apprentice'); }
  }, [guildMember?.id]);
  const [editing, setEditing] = React.useState(false);

  const specInfo = SPEC_ALL.find(s => s.name === spec);
  const levelIdx = SPEC_LEVELS_CH.indexOf(level);

  const FEATURES = {
    Apprentice: 'When performing actions with tools from your specialized discipline, gain profession modifier +2 as a bonus to skill checks.',
    Journeyman: 'When performing actions with tools from your specialized discipline, the result is improved based on your profession modifier.',
    Master: 'You spend half the usual time to perform actions with tools from your specialized discipline.',
    Grandmaster: 'When performing actions related to your specialized discipline, you have advantage on all related skill checks.',
  };

  return (
    <div style={{ maxWidth:640 }}>
      {/* Current spec header */}
      <div style={{ background:'#1c1c22', border:'1px solid #2a2a32', borderRadius:10, padding:'20px 24px', marginBottom:20 }}>
        <div style={{ display:'flex', justifyContent:'space-between', alignItems:'flex-start', marginBottom:16 }}>
          <div style={charStyles.cardTitle}>Specialization</div>
          <button style={charStyles.addBtn} onClick={()=>setEditing(!editing)}>{editing?'Done':'✎ Edit'}</button>
        </div>

        {editing ? (
          <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:12 }}>
            <div>
              <label style={{ fontSize:10,fontWeight:800,color:'#6b6966',textTransform:'uppercase',letterSpacing:'0.08em',display:'block',marginBottom:4 }}>Specialization</label>
              <select style={{ width:'100%',background:'#111116',border:'1px solid #3a3a42',borderRadius:6,color:'#e8e6e3',padding:'8px 10px',fontSize:13,fontFamily:"'Nunito',sans-serif" }}
                value={spec} onChange={e=>setSpec(e.target.value)}>
                <option value="">— None —</option>
                {SPEC_ALL.map(s=><option key={s.name} value={s.name}>{s.name}</option>)}
              </select>
            </div>
            <div>
              <label style={{ fontSize:10,fontWeight:800,color:'#6b6966',textTransform:'uppercase',letterSpacing:'0.08em',display:'block',marginBottom:4 }}>Level</label>
              <select style={{ width:'100%',background:'#111116',border:'1px solid #3a3a42',borderRadius:6,color:'#e8e6e3',padding:'8px 10px',fontSize:13,fontFamily:"'Nunito',sans-serif" }}
                value={level} onChange={e=>setLevel(e.target.value)}>
                {SPEC_LEVELS_CH.map(l=><option key={l} value={l}>{l}</option>)}
              </select>
            </div>
          </div>
        ) : spec ? (
          <div style={{ display:'flex', gap:16, alignItems:'flex-start' }}>
            <div style={{ flex:1 }}>
              <div style={{ fontFamily:"'Cinzel',serif", fontSize:20, fontWeight:800, color:'#e8e6e3', marginBottom:4 }}>{spec}</div>
              <div style={{ fontSize:12, color:'#9a9793', marginBottom:6 }}>Required: {specInfo?.tools}</div>
              <div style={{ fontSize:12, color:'#6b6966' }}>Key Skills: {specInfo?.skills}</div>
            </div>
            <div style={{ textAlign:'center', flexShrink:0 }}>
              <div style={{ fontSize:24, fontWeight:900, fontFamily:"'Cinzel',serif", color: SPEC_LVL_COLOR_CH[level] }}>{level}</div>
              <div style={{ fontSize:10, color:'#6b6966', marginTop:2 }}>Profession Level</div>
            </div>
          </div>
        ) : (
          <div style={{ color:'#4a4a52', fontSize:13, fontStyle:'italic' }}>No specialization chosen. Click ✎ Edit to assign one.</div>
        )}
      </div>

      {/* Feature unlocks */}
      {spec && (
        <div style={{ background:'#1c1c22', border:'1px solid #2a2a32', borderRadius:10, padding:'20px 24px', marginBottom:20 }}>
          <div style={charStyles.cardTitle}>Unlocked Features</div>
          <div style={{ display:'flex', flexDirection:'column', gap:10 }}>
            {SPEC_LEVELS_CH.map((l, i) => {
              const unlocked = i <= levelIdx;
              return (
                <div key={l} style={{ display:'flex', gap:12, alignItems:'flex-start', opacity: unlocked ? 1 : 0.35 }}>
                  <div style={{ width:24, height:24, borderRadius:5, background: unlocked ? `${SPEC_LVL_COLOR_CH[l]}22` : '#1a1a20', border:`1px solid ${unlocked?SPEC_LVL_COLOR_CH[l]+'44':'#2a2a32'}`, display:'flex', alignItems:'center', justifyContent:'center', fontSize:12, flexShrink:0, marginTop:1 }}>
                    {unlocked ? '✓' : '○'}
                  </div>
                  <div>
                    <div style={{ fontSize:12, fontWeight:800, color: unlocked ? SPEC_LVL_COLOR_CH[l] : '#3a3a42', textTransform:'uppercase', letterSpacing:'0.08em', marginBottom:3 }}>{l}+</div>
                    <div style={{ fontSize:13, color: unlocked ? '#c5c3c0' : '#3a3a42', lineHeight:1.6 }}>{FEATURES[l]}</div>
                  </div>
                </div>
              );
            })}
          </div>
        </div>
      )}

      {/* Guild membership */}
      {guild && (
        <div style={{ background:'#1c1c22', border:'1px solid #2a2a32', borderRadius:10, padding:'20px 24px' }}>
          <div style={charStyles.cardTitle}>Guild Membership</div>
          <div style={{ display:'flex', gap:10, alignItems:'center' }}>
            <div style={{ fontFamily:"'Cinzel',serif", fontSize:16, fontWeight:800, color:'#c9a227' }}>{guild.name}</div>
            <span style={{ fontSize:11, fontWeight:800, color:'#c9a227', background:'rgba(201,162,39,0.1)', border:'1px solid rgba(201,162,39,0.25)', borderRadius:4, padding:'2px 8px' }}>Rank {guild.rank}</span>
          </div>
          <div style={{ fontSize:12, color:'#9a9793', marginTop:4 }}>Base: {guild.baseCityName || '—'} · Role: {guildMember?.role}</div>
        </div>
      )}
    </div>
  );
};

const charStyles = {
  page: { display:'flex', flexDirection:'column', height:'100%', overflow:'hidden', fontFamily:"'Nunito',sans-serif" },
  hero: { background:'linear-gradient(135deg,#1a0808 0%,#111116 100%)', padding:'20px 32px', borderBottom:'1px solid #2a2a32', flexShrink:0 },
  backBtn: { background:'none', border:'none', color:'#9a9793', cursor:'pointer', fontSize:13, fontWeight:700, padding:'0 0 12px', display:'block' },
  heroMain: { display:'flex', alignItems:'center', gap:16, marginBottom:16 },
  heroAvatar: { width:56, height:56, borderRadius:10, background:'#2a2a32', border:'2px solid #c9a22744', display:'flex', alignItems:'center', justifyContent:'center', fontSize:18, fontWeight:800, color:'#c9a227', flexShrink:0 },
  heroName: { fontFamily:"'Cinzel',serif", fontSize:22, fontWeight:700, color:'#e8e6e3', margin:'0 0 4px' },
  heroMeta: { fontSize:13, color:'#9a9793' },
  wealthBar: { display:'flex', gap:10 },
  wealthChip: { background:'#1c1c22', border:'1px solid #2a2a32', borderRadius:8, padding:'8px 16px', display:'flex', alignItems:'center', gap:8 },
  gpLabel: { fontSize:11, fontWeight:800, color:'#c9a227', textTransform:'uppercase', letterSpacing:'0.1em' },
  gpValue: { fontSize:20, fontWeight:800, color:'#e8e6e3', fontFamily:"'Cinzel',serif" },
  tabs: { display:'flex', borderBottom:'1px solid #2a2a32', background:'#16161b', flexShrink:0 },
  tab: { background:'none', borderTop:'none', borderLeft:'none', borderRight:'none', borderBottomWidth:2, borderBottomStyle:'solid', borderBottomColor:'transparent', color:'#6b6966', padding:'11px 20px', cursor:'pointer', fontSize:13, fontWeight:600, fontFamily:"'Nunito',sans-serif" },
  tabActive: { color:'#e8e6e3', borderBottomColor:'#c9a227' },
  content: { flex:1, overflowY:'auto', padding:'24px 32px' },
  card: { background:'#1c1c22', border:'1px solid #2a2a32', borderRadius:10, padding:'20px 24px' },
  cardTitle: { fontSize:12, fontWeight:800, color:'#9a9793', textTransform:'uppercase', letterSpacing:'0.1em', marginBottom:14 },
  coinBlock: { background:'#111116', border:'1px solid', borderRadius:8, padding:'16px', textAlign:'center' },
  materialRow: { display:'flex', gap:14, alignItems:'flex-start', background:'#1c1c22', border:'1px solid #2a2a32', borderRadius:8, padding:'14px 18px' },
  materialIcon: { fontSize:16, color:'#c9a227', marginTop:2, flexShrink:0 },
  addBtn: { background:'rgba(197,48,48,0.15)', border:'1px solid #c53030', color:'#e8e6e3', borderRadius:6, padding:'6px 14px', cursor:'pointer', fontSize:12, fontWeight:700, fontFamily:"'Nunito',sans-serif" },
  spellRow: { display:'flex', gap:12, alignItems:'center', background:'#111116', border:'1px solid #2a2a32', borderRadius:8, padding:'10px 14px' },
  spellLevel: { width:28, height:28, borderRadius:6, display:'flex', alignItems:'center', justifyContent:'center', fontSize:12, fontWeight:800, flexShrink:0 },
  preparedBadge: { fontSize:11, color:'#c9a227', fontWeight:700 },
};

Object.assign(window, { CharacterView, charStyles });
