// comanda-produse.jsx — cele doua foi care ies din fila „Produse" a unei campanii.
//
// Sunt campanii in care creatorii nu primesc bani, ci produse. Pana acum, cine
// facea campania completa produsele o data in Anexa 1 a contractului si apoi tinea
// minte pe hartie ce produs merge la cine. Din aceleasi date ies aici doua foi:
//
//   fel="brand"  — FISA DE COMANDA. Ce sa ne trimita brandul si cate bucati.
//                  Numele creatorilor apar (sunt oricum in Anexa 1 a contractului),
//                  dar NICIO adresa si NICIUN telefon.
//   fel="intern" — LISTA DE DISTRIBUTIE. Cine primeste ce pachet, cu adresa si
//                  telefonul, pentru cine ambaleaza la sediu.
//
// De ce sunt doua si nu una: produsele vin toate la sediul agentiei si le
// distribuim noi. Daca brandul ar livra direct la creatori, ar ramane cu adresele
// si telefoanele lor si i-ar putea contacta pe viitor fara noi. Impartirea in doua
// foi nu e o preferinta de asezare — e motivul pentru care exista fisa.
//
// Printarea: acelasi mecanism ca la rapoarte (vezi campaign-report.jsx). Foaia se
// deseneaza intr-un portal lipit de <body> si refoloseste clasele
// .report-print-root / .report-toolbar / .report-sheet, deci regulile de @media
// print din styles.css se aplica aproape fara nimic in plus — singura adaugare e
// blocul .cp-tabel-lung de la coada lui styles.css, pentru tabelul care poate
// depasi o pagina.
//
// Expune:
//   window.ComandaProduseFoaie({ campaign, brand, creators, influencers, fel, onClose })

const { useState: useStateCP, useEffect: useEffectCP } = React;

function cpFmt(v) {
  if (v == null || v === '' || Number.isNaN(Number(v))) return '—';
  return Number(v).toLocaleString('ro-RO');
}

function cpData(d) {
  if (!d) return '—';
  const x = new Date(String(d).length === 10 ? d + 'T00:00:00' : d);
  return isNaN(x.getTime()) ? '—' : x.toLocaleDateString('ro-RO');
}

function cpGol(p) {
  return !String(p.cod || '').trim() && !String(p.denumire || '').trim();
}

// Adresa de livrare, pe linii separate. Un pachet se ambaleaza citind o eticheta,
// nu un paragraf, deci nu le lipim cu virgule intr-un singur rand.
function cpAdresa(inf) {
  if (!inf) return [];
  const oras = [inf.city, inf.county].filter(x => x && String(x).trim()).join(', ');
  return [inf.address, oras, inf.country].filter(x => x && String(x).trim());
}

// „Are adresa" inseamna are STRADA, nu are orice. Aproape toti creatorii au trecut
// orasul si tara din formularul de inscriere, deci o verificare pe lista de linii
// ar spune ca toata lumea poate primi pachetul — si abia in ziua ambalarii s-ar
// vedea ca de fapt nu stim unde sa-l trimitem.
function cpAreStrada(inf) {
  return !!inf && !!String(inf.address || '').trim();
}

// Cat se comanda in total din fiecare produs.
//
// Gruparea se face pe COD, nu pe (cod + denumire). Daca doi colegi scriu acelasi
// cod cu denumiri putin diferite — „Ser 30ml" si „Ser hidratant 30 ml" — o grupare
// pe amandoua ar scoate doua randuri in comanda si brandul ar trimite dublu.
// Cand codul lipseste, cade inapoi pe denumire, ca randul sa nu se piarda.
function cpTotaluri(produse) {
  const dupaCheie = new Map();
  produse.forEach(p => {
    if (cpGol(p)) return;
    const cod = String(p.cod || '').trim();
    const den = String(p.denumire || '').trim();
    const cheie = (cod || den).toLowerCase();
    if (!dupaCheie.has(cheie)) dupaCheie.set(cheie, { cod: cod, denumiri: new Set(), cantitate: 0, creatori: new Set() });
    const x = dupaCheie.get(cheie);
    x.cantitate += Number(p.cantitate) || 0;
    x.creatori.add(p.campaign_creator_id);
    if (!x.cod && cod) x.cod = cod;
    // TOATE denumirile distincte ale codului, nu doar prima intalnita. Daca brandul
    // refoloseste un cod pentru doua produse, a doua denumire trebuie sa apara si
    // ea — altfel produsul dispare din comanda si nu-l mai trimite nimeni.
    if (den) x.denumiri.add(den);
  });
  return Array.from(dupaCheie.values())
    .map(x => Object.assign({}, x, { denumire: Array.from(x.denumiri).join(' / ') }))
    .sort((a, b) => (a.cod || a.denumire).localeCompare(b.cod || b.denumire, 'ro'));
}

function ComandaProduseFoaie({ campaign, brand, creators, influencers, fel, onClose }) {
  const [produse, setProduse] = useStateCP([]);
  const [seIncarca, setSeIncarca] = useStateCP(true);
  // „N-am putut citi" si „nu exista produse" sunt lucruri diferite, iar foaia asta
  // ajunge la un client: nu are voie sa spuna ca nu e nimic de comandat cand de
  // fapt nu stie.
  const [eroare, setEroare] = useStateCP('');

  const intern = fel === 'intern';
  const titlu = intern ? 'Listă de distribuție' : 'Fișă de comandă produse';

  // Produsele se citesc din baza, nu din starea filei: foaia asta ajunge pe hartie
  // la un client, deci trebuie sa arate ce e SALVAT, nu ce e tastat pe ecran.
  useEffectCP(() => {
    (async () => {
      const ids = creators.map(c => c.id);
      if (ids.length === 0) { setSeIncarca(false); return; }
      const { data, error } = await window.sb.from('campaign_products')
        .select('*').in('campaign_creator_id', ids).order('position');
      if (error) { setEroare(window.mesajEroare(error)); setSeIncarca(false); return; }
      setProduse((data || []).filter(p => !cpGol(p)));
      setSeIncarca(false);
    })();
  }, [campaign.id, fel]);

  window.useEscape(onClose);

  const infDupaAlocare = (ccId) => {
    const cc = creators.find(c => c.id === ccId);
    return cc ? influencers.find(i => i.id === cc.influencer_id) : null;
  };

  // Doar creatorii care chiar primesc ceva. Cine e alocat pe campanie dar n-are
  // niciun produs trecut nu are ce cauta intr-o comanda.
  const grupuri = creators
    .map(cc => ({ cc: cc, inf: infDupaAlocare(cc.id), randuri: produse.filter(p => p.campaign_creator_id === cc.id) }))
    .filter(g => g.randuri.length > 0)
    .sort((a, b) => (a.inf ? a.inf.full_name : '').localeCompare(b.inf ? b.inf.full_name : '', 'ro'));

  const totaluri = cpTotaluri(produse);
  const totalBucati = totaluri.reduce((s, t) => s + t.cantitate, 0);
  const brandName = brand ? (brand.brand || brand.company) : '—';

  // Cine n-are adresa in fisa nu poate primi pachetul. Se spune INAINTE de lista,
  // ca sa se afle la birou si nu in ziua ambalarii.
  const faraAdresa = intern ? grupuri.filter(g => !cpAreStrada(g.inf)) : [];

  const accent = intern ? '#B45309' : '#18181b';

  return ReactDOM.createPortal(
    <div className="report-print-root" style={{
      position: 'fixed', inset: 0, zIndex: 400, overflowY: 'auto',
      background: '#f4f4f5', padding: '24px 16px',
    }}>
      <div className="report-toolbar" style={{
        position: 'sticky', top: 0, zIndex: 2, maxWidth: 920, margin: '0 auto 16px',
        display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 12,
        padding: '12px 16px', borderRadius: 10, background: '#18181b', color: '#fff', flexWrap: 'wrap',
      }}>
        <div style={{ fontSize: 13, color: eroare ? '#FCA5A5' : undefined }}>
          {eroare ? 'Nu am putut citi produsele: ' + eroare : (seIncarca ? 'Se încarcă produsele...' : (intern
            ? 'Foaie internă, pentru cine ambalează. Nu se trimite brandului.'
            : 'Gata de trimis brandului. Alege „Salvează ca PDF" în fereastra de printare.'))}
        </div>
        <div style={{ display: 'flex', gap: 8 }}>
          {/* ── 10: numele fisierului PDF ──
              Chrome si Edge propun la „Salveaza ca PDF" exact `document.title`, iar
              in tot panoul acela e mereu „4U Media Admin". Cele doua foi ieseau cu
              acelasi nume, deci lista interna cu adrese si telefoane putea ajunge
              atasata la brand dintr-o confuzie de fisiere. Titlul se pune inainte
              de print si se da inapoi dupa. */}
          <button onClick={() => {
            const titluVechi = document.title;
            document.title = (intern ? 'INTERN - lista distributie - ' : 'Comanda produse - ') + campaign.name;
            window.print();
            document.title = titluVechi;
          }} disabled={seIncarca || !!eroare} style={{
            padding: '8px 16px', borderRadius: 8, border: 'none', cursor: (seIncarca || eroare) ? 'not-allowed' : 'pointer',
            background: '#52F20F', color: '#000', fontWeight: 600, fontSize: 13, opacity: (seIncarca || eroare) ? .5 : 1,
          }}>Printează / Salvează PDF</button>
          <button onClick={onClose} style={{
            padding: '8px 16px', borderRadius: 8, border: '1px solid rgba(255,255,255,.2)',
            background: 'transparent', color: '#fff', cursor: 'pointer', fontSize: 13,
          }}>Închide</button>
        </div>
      </div>

      <div className="report-sheet" style={{
        maxWidth: 920, margin: '0 auto', background: '#fff', color: '#18181b',
        padding: '40px 44px', borderRadius: 10, boxShadow: '0 2px 24px rgba(0,0,0,.12)',
        fontFamily: "'Geist', system-ui, sans-serif", lineHeight: 1.55,
      }}>
        {/* Antet */}
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', gap: 20, borderBottom: '2px solid ' + accent, paddingBottom: 16, marginBottom: 24 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
            <img src="uploads/4u-logo-96.png" alt="" width="44" height="44"
              style={{ width: 44, height: 44, borderRadius: 10, display: 'block', flexShrink: 0 }} />
            <div>
              <div style={{ fontSize: 20, fontWeight: 800, letterSpacing: '-.02em' }}>4U Agency</div>
              <div style={{ fontSize: 11, color: '#71717a', letterSpacing: '.08em', textTransform: 'uppercase', marginTop: 2 }}>Agenție de influencer marketing</div>
            </div>
          </div>
          <div style={{ textAlign: 'right' }}>
            <div style={{ fontSize: 11, color: accent, letterSpacing: '.12em', textTransform: 'uppercase', fontWeight: 700 }}>{titlu}</div>
            <div style={{ fontSize: 12, color: '#3f3f46', marginTop: 2 }}>Generată la {new Date().toLocaleDateString('ro-RO')}</div>
          </div>
        </div>

        {/* Banda de avertisment, numai pe foaia interna. Cele doua foi ies din
            aceleasi date si arata asemanator; una are adrese si telefoane, alta nu.
            Banda exista ca sa nu plece niciodata cea gresita catre brand. */}
        {intern && (
          <div style={{
            border: '1px solid #FCD34D', borderLeft: '4px solid #B45309', borderRadius: 8,
            background: '#FFFBEB', padding: '12px 16px', marginBottom: 22,
            fontSize: 12, color: '#78350F', lineHeight: 1.5,
          }}>
            <strong>Document intern.</strong> Conține adresele și telefoanele creatorilor.
            Nu se trimite brandului și nu se atașează la contract. Pentru brand există
            „Fișa de comandă", care nu are date de contact.
          </div>
        )}

        <h1 style={{ fontSize: 26, margin: '0 0 6px', fontWeight: 700, letterSpacing: '-.02em' }}>{campaign.name}</h1>
        <div style={{ fontSize: 13, color: '#52525b', marginBottom: 24 }}>
          Brand: <strong style={{ color: '#18181b' }}>{brandName}</strong>
          {campaign.produse_contract_nr && <span> · Anexă la contractul nr. <strong style={{ color: '#18181b' }}>{campaign.produse_contract_nr}</strong></span>}
          {campaign.produse_contract_data && <span> din {cpData(campaign.produse_contract_data)}</span>}
        </div>

        {/* Unde se livreaza. Numai pe foaia catre brand: e singurul lucru pe care
            il cerem de la ei si singura regula care nu se negociaza. */}
        {!intern && (
          <div style={{
            border: '1px solid #e4e4e7', borderLeft: '4px solid #18181b', borderRadius: 8,
            padding: '16px 18px', background: '#fafafa', marginBottom: 26,
          }}>
            <div style={{ fontSize: 10, color: '#71717a', textTransform: 'uppercase', letterSpacing: '.08em', marginBottom: 4 }}>Termen și loc de livrare</div>
            <div style={{ fontSize: 15, fontWeight: 600 }}>
              {campaign.produse_termen_livrare || 'La sediul 4U Agency (de completat)'}
            </div>
            <div style={{ fontSize: 12, color: '#52525b', marginTop: 8, lineHeight: 1.5 }}>
              Toate produsele se livrează la adresa de mai sus. Distribuția către creatori
              se face de către agenție, pe baza listei interne de distribuție.
            </div>
            {campaign.produse_contact_client && (
              <div style={{ fontSize: 12, color: '#52525b', marginTop: 6 }}>
                Persoană de contact din partea clientului: <strong style={{ color: '#18181b' }}>{campaign.produse_contact_client}</strong>
              </div>
            )}
          </div>
        )}

        {eroare ? (
          <div style={{ padding: '28px 0', fontSize: 13, color: '#B91C1C', lineHeight: 1.6 }}>
            Nu am putut citi produsele campaniei: {eroare}<br />
            Foaia nu se poate genera acum. Închide, verifică internetul și încearcă din nou.
          </div>
        ) : seIncarca ? (
          <div style={{ padding: 40, textAlign: 'center', color: '#71717a' }}>Se încarcă produsele...</div>
        ) : produse.length === 0 ? (
          <div style={{ padding: '28px 0', fontSize: 13, color: '#71717a' }}>
            Niciun produs trecut pe campania asta. Completează tabelul din fila „Produse"
            și generează foaia din nou.
          </div>
        ) : intern ? (
          <React.Fragment>
            {faraAdresa.length > 0 && (
              <div className="report-creator" style={{
                border: '1px solid #FCA5A5', borderRadius: 8, background: '#FEF2F2',
                padding: '14px 16px', marginBottom: 20, fontSize: 12, color: '#7F1D1D', lineHeight: 1.6,
              }}>
                <strong>Nu se poate expedia încă:</strong> {faraAdresa.length === 1 ? 'un creator nu are stradă și număr' : faraAdresa.length + ' creatori nu au stradă și număr'} în fișă —
                {' '}{faraAdresa.map(g => (g.inf ? g.inf.full_name : 'creator șters')).join(', ')}.
                {' '}Completează adresa în fișa creatorului, apoi generează lista din nou.
              </div>
            )}

            <CpTitluSectiune>Pachete de pregătit ({grupuri.length})</CpTitluSectiune>
            {grupuri.map((g, i) => {
              const linii = cpAdresa(g.inf);
              return (
                <div key={g.cc.id} className="report-creator" style={{
                  border: '1px solid #e4e4e7', borderRadius: 8, padding: 16, marginBottom: 12,
                  display: 'flex', gap: 16, alignItems: 'flex-start',
                }}>
                  {/* Numarul pachetului: ca sa se poata striga „lipsește 7", nu
                      „lipsește al lui Cristian, sau Cătălin, nu mai știu". */}
                  <div style={{
                    flexShrink: 0, width: 30, height: 30, borderRadius: 8, background: '#18181b', color: '#fff',
                    display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 13, fontWeight: 700,
                  }}>{i + 1}</div>

                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ fontSize: 15, fontWeight: 700 }}>
                      {g.inf ? g.inf.full_name : 'Creator șters'}
                      {g.inf && g.inf.tiktok_handle && <span style={{ fontWeight: 400, color: '#52525b', marginLeft: 8 }}>@{g.inf.tiktok_handle}</span>}
                    </div>
                    <div style={{ fontSize: 12, color: '#3f3f46', marginTop: 4, lineHeight: 1.6 }}>
                      {g.inf && g.inf.phone
                        ? <div>Telefon: <strong>{g.inf.phone}</strong></div>
                        : <div style={{ color: '#B91C1C' }}>Fără telefon în fișă</div>}
                      {linii.map((l, k) => <div key={k}>{l}</div>)}
                      {!cpAreStrada(g.inf) && (
                        <div style={{ color: '#B91C1C', fontWeight: 600 }}>Fără stradă și număr în fișă — pachetul nu poate fi expediat</div>
                      )}
                    </div>

                    <CpTabel
                      lung={false}
                      cap={['Cod', 'Produs', 'Cant.']}
                      aliniere={['left', 'left', 'right']}
                      randuri={g.randuri.map(p => [p.cod || '—', p.denumire || '—', cpFmt(p.cantitate)])}
                    />
                  </div>

                  {/* Doua casete si un rand de scris: foaia asta se tine in mana
                      langa cutii, deci are nevoie de loc pentru pix. */}
                  <div style={{ flexShrink: 0, width: 150, fontSize: 11, color: '#52525b' }}>
                    <div style={{ display: 'flex', gap: 12, marginBottom: 10 }}>
                      <span><span style={{ display: 'inline-block', width: 12, height: 12, border: '1px solid #a1a1aa', borderRadius: 3, marginRight: 5, verticalAlign: '-2px' }} />ambalat</span>
                      <span><span style={{ display: 'inline-block', width: 12, height: 12, border: '1px solid #a1a1aa', borderRadius: 3, marginRight: 5, verticalAlign: '-2px' }} />expediat</span>
                    </div>
                    <div>AWB</div>
                    <div style={{ borderBottom: '1px solid #a1a1aa', height: 18 }} />
                  </div>
                </div>
              );
            })}
          </React.Fragment>
        ) : (
          <React.Fragment>
            {/* Ce comanda brandul. Prima, pentru ca e singurul tabel de care are
                nevoie ca sa pregateasca marfa. */}
            <CpTitluSectiune>De comandat — total pe produs</CpTitluSectiune>
            <CpTabel
              lung={false}
              cap={['Cod produs', 'Denumire / descriere', 'Cantitate', 'Creatori']}
              aliniere={['left', 'left', 'right', 'right']}
              randuri={totaluri.map(t => [t.cod || '—', t.denumire || '—', cpFmt(t.cantitate), String(t.creatori.size)])}
              subsol={['', 'Total', cpFmt(totalBucati) + ' buc.', String(grupuri.length)]}
            />

            <div style={{ height: 26 }} />

            {/* Desfasurarea pe creator. Nu e pentru livrare — brandul nu trimite la
                creatori — e ca sa se vada ca ce se comanda si ce s-a semnat in Anexa 1
                sunt acelasi lucru. De aceea are nume, dar nici adrese, nici telefoane. */}
            <CpTitluSectiune>Desfășurare pe creator ({grupuri.length})</CpTitluSectiune>
            <CpTabel
              lung={true}
              cap={['Creator', 'Cod produs', 'Denumire / descriere', 'Cant.']}
              aliniere={['left', 'left', 'left', 'right']}
              grupuri={grupuri.map(g => g.randuri.map((p, k) => [
                // Numele o singura data pe grup: repetat pe fiecare rand, tabelul
                // se citeste ca o lista de produse, nu de oameni.
                k === 0 ? (g.inf ? g.inf.full_name : 'Creator șters') : '',
                p.cod || '—', p.denumire || '—', cpFmt(p.cantitate),
              ]))}
            />

            <div style={{ fontSize: 11, color: '#71717a', marginTop: 10, lineHeight: 1.6 }}>
              Numele creatorilor sunt cele din Anexa 1 a contractului. Datele lor de
              contact nu fac obiectul acestei fișe: produsele se livrează la sediul
              agenției, iar distribuția o face agenția.
            </div>

            <CpSemnaturi contactClient={campaign.produse_contact_client} />
          </React.Fragment>
        )}

        <div style={{ marginTop: 28, paddingTop: 14, borderTop: '1px solid #e4e4e7', fontSize: 11, color: '#71717a' }}>
          {intern
            ? 'Listă generată automat din panoul intern 4U Agency. Document intern — nu se transmite în afara agenției.'
            : 'Fișă generată automat din panoul intern 4U Agency, pe baza produselor înregistrate la data generării.'}
        </div>
      </div>
    </div>,
    document.body
  );
}

function CpTitluSectiune({ children }) {
  return (
    <h2 style={{
      fontSize: 11, letterSpacing: '.14em', textTransform: 'uppercase', color: '#71717a',
      margin: '0 0 12px', fontWeight: 600,
    }}>{children}</h2>
  );
}

// Tabelul foilor. `lung` marcheaza tabelul care poate trece de o pagina: acela are
// nevoie de capul de tabel repetat la fiecare pagina si de voie sa se rupa, altfel
// regula generala din @media print („tabelele nu se taie") l-ar arunca intreg pe
// pagina urmatoare si ar ramane o foaie aproape goala.
function CpTabel({ cap, randuri, grupuri, aliniere, subsol, lung }) {
  const al = (j) => (aliniere && aliniere[j]) || (j === 0 ? 'left' : 'right');
  const celule = (r, i) => (
    <tr key={i}>
      {r.map((cell, j) => (
        <td key={j} style={{
          padding: '7px 8px', borderBottom: '1px solid #f4f4f5', textAlign: al(j),
          fontVariantNumeric: al(j) === 'right' ? 'tabular-nums' : 'normal',
          fontWeight: j === 0 && cell ? 600 : 400,
        }}>{cell}</td>
      ))}
    </tr>
  );
  return (
    <table className={lung ? 'cp-tabel-lung' : ''} style={{ width: '100%', borderCollapse: 'collapse', fontSize: 12, marginTop: 8 }}>
      <thead>
        <tr>
          {cap.map((h, j) => (
            <th key={j} style={{
              textAlign: al(j), padding: '7px 8px', background: '#fafafa',
              borderBottom: '1px solid #e4e4e7', fontWeight: 600, color: '#3f3f46', fontSize: 11,
            }}>{h}</th>
          ))}
        </tr>
      </thead>
      {/* Cate un <tbody> pe creator cand primim grupuri: numele lui se scrie o
          singura data, pe primul rand, deci randurile de sub el n-au voie sa ajunga
          singure pe pagina urmatoare. Fara grupuri, un singur tbody, ca inainte. */}
      {grupuri
        ? grupuri.map((g, gi) => <tbody key={gi}>{g.map((r, i) => celule(r, i))}</tbody>)
        : <tbody>{randuri.map((r, i) => celule(r, i))}</tbody>}
      {subsol && (
        <tfoot>
          <tr>
            {subsol.map((cell, j) => (
              <td key={j} style={{
                padding: '9px 8px', borderTop: '2px solid #18181b', textAlign: al(j),
                fontWeight: 700, fontSize: 12,
                fontVariantNumeric: al(j) === 'right' ? 'tabular-nums' : 'normal',
              }}>{cell}</td>
            ))}
          </tr>
        </tfoot>
      )}
    </table>
  );
}

// Anexa 1 din contract se semneaza de amandoua partile, deci si fisa care o
// insoteste are unde. Cele doua blocuri se tin impreuna la printare: doua nume pe
// o pagina si doua linii goale pe urmatoarea nu inseamna nimic.
function CpSemnaturi({ contactClient }) {
  const bloc = (titlu, subtitlu) => (
    <div style={{ flex: 1 }}>
      <div style={{ fontSize: 10, color: '#71717a', textTransform: 'uppercase', letterSpacing: '.08em', marginBottom: 22 }}>{titlu}</div>
      <div style={{ borderTop: '1px solid #a1a1aa', paddingTop: 6, fontSize: 11, color: '#52525b' }}>
        {subtitlu || 'Nume, semnătură, dată'}
      </div>
    </div>
  );
  return (
    <div className="report-creator" style={{ display: 'flex', gap: 40, marginTop: 34 }}>
      {bloc('Din partea agenției')}
      {bloc('Din partea clientului', contactClient ? contactClient + ' — semnătură, dată' : null)}
    </div>
  );
}

window.ComandaProduseFoaie = ComandaProduseFoaie;
