const $ = id => document.getElementById(id);
const plans = [{id:'free',name:'Free',seats:1,price:'0',relay:1},{id:'solo',name:'Individuel',seats:1,price:'0,99',ttc:'1,20',relay:5},{id:'team',name:'Entreprise 10',seats:10,price:'4,99',ttc:'6,04',relay:25},{id:'business',name:'Entreprise 100',seats:100,price:'24,99',ttc:'30,24',relay:100}];
let state = null;
const message = (text, error = false) => { $('message').textContent=text; $('message').classList.toggle('error',error); };
const date = value => value ? new Date(value).toLocaleDateString('fr-BE') : '—';
const gb = bytes => `${((bytes || 0)/1e9).toLocaleString('fr-BE',{maximumFractionDigits:2})} Go`;
async function api(path, body) { const res=await fetch(path,{credentials:'same-origin',...(body!==undefined?{method:'POST',headers:{'Content-Type':'application/json',...(state?.csrfToken?{'X-CSRF-Token':state.csrfToken}:{})},body:JSON.stringify(body)}:{})});const data=await res.json();if(!res.ok)throw Object.assign(new Error(data.error || 'Service indisponible.'),{status:res.status});return data; }
function el(tag,text,className){const node=document.createElement(tag);if(text!==undefined)node.textContent=text;if(className)node.className=className;return node;}
function button(text,handler,className='secondary'){const node=el('button',text,`button ${className}`);node.type='button';node.addEventListener('click',()=>run(node,handler));return node;}
async function run(node,fn){node.disabled=true;try{await fn();}catch(error){message(error.message,true);}finally{node.disabled=false;}}
function confirmAction(text){$('confirm-text').textContent=text;const dialog=$('confirm-dialog');dialog.returnValue='cancel';dialog.showModal();return new Promise(resolve=>dialog.addEventListener('close',()=>resolve(dialog.returnValue==='confirm'),{once:true}));}
function redirectStripe(url){const target=new URL(url);if(!['https://checkout.stripe.com','https://billing.stripe.com'].includes(target.origin))throw new Error('Lien de paiement refusé.');location.assign(target.href);}
async function refresh(){state=await api('/api/account/me');render();}
async function portal(){if(state?.subscription?.complimentary)throw new Error('Votre accès propriétaire est offert et ne nécessite aucun abonnement Stripe.');redirectStripe((await api('/api/billing/portal',{})).url);}
function renderPlans(){
  const root=$('plans');root.replaceChildren();$('offers').hidden=Boolean(state?.subscription?.complimentary);if(state?.subscription?.complimentary)return;
  for(const plan of plans){
    const free=plan.id==='free', paidSubscriber=Boolean(state?.subscription?.plan&&state.subscription.plan!=='free');
    const card=el('article',undefined,'price-card');card.append(el('h3',plan.name));
    const price=el('p',`${plan.price} € `,'price');price.append(el('span',free?'/ mois':'HT / mois'));
    card.append(price,el('p',free?'Sans carte bancaire. Sans limite de durée.':`${plan.ttc} € TTC avec 21 % de TVA.`,'tax'));
    const list=el('ul');for(const text of [`${plan.seats} licence${plan.seats>1?'s':''} pour ${plan.seats} ordinateur${plan.seats>1?'s':''}`,free?'3 liens par mois · expiration à 24 h':'Liens sans quota mensuel · expiration jusqu’à 7 jours',`${plan.relay} Go de relais partagés par mois`,'Réception gratuite, sans application','Attribution et activation des postes'])list.append(el('li',text));if(['team','business'].includes(plan.id))list.append(el('li','Page de réception aux couleurs de votre entreprise'));card.append(list);
    const choose=button(free?(state?(paidSubscriber?'Free après votre abonnement':'Votre offre gratuite'):'Créer mon compte gratuit'):(paidSubscriber?'Gérer mon offre':`Choisir ${plan.name}`),async()=>{
      if(!state){$('email').focus();message(free?'Créez votre compte gratuit, sans carte bancaire.':'Créez votre compte ou connectez-vous pour choisir cette offre.');return;}
      if(free){if(paidSubscriber)message('Pour revenir à Free, annulez le renouvellement de votre abonnement dans le portail Stripe. Votre accès payant reste disponible jusqu’à sa date de fin.');return;}
      if(paidSubscriber)return portal();
      redirectStripe((await api('/api/billing/checkout',{plan:plan.id})).url);
    },'primary');
    choose.disabled=free?Boolean(state&&!paidSubscriber):Boolean(state&&!state.billingEnabled);card.append(choose);root.append(card);
  }
}
function previewBranding(){
  const accent=/^#[0-9a-f]{6}$/i.test($('branding-accent').value)?$('branding-accent').value:'#24513c';
  $('branding-preview-name').textContent=$('branding-company').value.trim()||'Votre entreprise';
  $('branding-preview-message').textContent=$('branding-message').value.trim()||'Votre message d’accueil apparaîtra ici.';
  $('branding-preview-accent').style.backgroundColor=accent;
  $('branding-accent-value').textContent=accent;
}
function renderBranding(){
  const enabled=Boolean(state?.brandingEnabled&&['team','business'].includes(state?.subscription?.plan)&&state?.subscription?.slots);
  $('branding-form').hidden=!enabled;$('branding-upgrade').hidden=enabled;
  const branding=state?.branding||{};
  $('branding-company').value=branding.companyName||'';$('branding-message').value=branding.message||'';
  $('branding-accent').value=/^#[0-9a-f]{6}$/i.test(branding.accent||'')?branding.accent:'#24513c';
  previewBranding();
}
let adminRequest=0;
async function loadAdmin(){
  const request=++adminRequest, accountId=state?.account?.id;
  if(state?.account?.role!=='admin')return;
  $('admin-status').textContent='Chargement…';
  try{
    const data=await api('/api/admin/overview');
    if(request!==adminRequest||state?.account?.id!==accountId||state?.account?.role!=='admin')return;
    $('admin-total').textContent=data.totalAccounts??data.stats?.totalAccounts??0;
    $('admin-devices').textContent=data.activeDevices??data.stats?.activeDevices??0;
    const root=$('admin-accounts');root.replaceChildren();
    for(const account of (data.accounts||[]).slice(0,50)){
      const row=el('tr');for(const value of [account.email,account.role==='admin'?'Administrateur':'Client',plans.find(p=>p.id===account.plan)?.name||account.plan||'—',account.slots??0,account.activeDevices??0,date(account.created)])row.append(el('td',String(value)));root.append(row);
    }
    $('admin-status').textContent='Les 50 comptes les plus récents au maximum. Vue en lecture seule.';
  }catch(error){if(request===adminRequest&&state?.account?.role==='admin')$('admin-status').textContent=error.message;}
}
function renderAdmin(){
  adminRequest++;const admin=state?.account?.role==='admin';$('administration').hidden=!admin;
  $('admin-accounts').replaceChildren();$('admin-total').textContent='—';$('admin-devices').textContent='—';$('admin-status').textContent='';
  if(admin)void loadAdmin();
}
function render(){ renderAdmin();$('auth').hidden=Boolean(state);$('dashboard').hidden=!state;renderPlans();if(!state)return;$('account-email').textContent=state.account.email;renderBranding();const sub=state.subscription,active=Boolean(sub?.slots),plan=plans.find(p=>p.id===sub?.plan);const free=sub?.plan==='free', complimentary=Boolean(sub?.complimentary), paid=Boolean(sub&&!free&&!complimentary);
$('subscription-status').textContent=complimentary?'Administrateur · Accès propriétaire':free?'Free · Gratuit':active?'Actif':'Sans abonnement actif';
$('subscription-detail').textContent=complimentary?'Entreprise 100 · 100 postes · Accès offert permanent.':free?'Free · 1 poste · gratuit sans limite de durée et sans carte bancaire.':active?`${plan?.name || 'Abonnement'} · ${sub.slots} poste${sub.slots>1?'s':''} · ${sub.cancelAtPeriodEnd?'Annulation prévue, accès jusqu’au':'Période payée jusqu’au'} ${date(sub.currentPeriodEnd)}.`:'Aucune licence disponible actuellement. Actualisez votre compte.';
$('billing-notice').textContent=complimentary?'Aucun paiement ni renouvellement nécessaire pour votre accès propriétaire.':state.billingEnabled?(free?'Vous pouvez passer à une offre payante ci-dessous. Votre compte Free reste gratuit.':'Paiements, factures et gestion de l’abonnement via Stripe.'):'Free est disponible. Les offres payantes ouvriront après configuration de Stripe.';
for(const id of ['portal','cancel']){$(id).hidden=!paid;$(id).disabled=!state.billingEnabled||!paid;}
$('billing-help').hidden=!paid;
$('transfer-count').textContent=free?`${state.transfersUsed||0} / ${state.transfersLimit??3}`:'Sans quota mensuel';
$('transfer-detail').textContent=free?`Liens créés en ${state.transferPeriod||'ce mois'} (mois civil UTC). Chaque lien expire au plus tard après 24 heures. Le compteur se renouvelle chaque mois ; un lien peut contenir plusieurs fichiers.`:'Pas de quota commercial mensuel sur les liens. Jusqu’à 10 liens actifs par poste, avec une expiration maximale de 7 jours.';
$('seat-count').textContent=sub?.slots||0;$('active-count').textContent=state.licenses.filter(l=>l.entitled&&l.status==='activated').length;$('relay-count').textContent=gb(state.relayUsedBytes);$('relay-detail').textContent=`Quota commun : ${gb(state.relayLimitBytes)} pour ${state.relayPeriod || 'ce mois'}, mois civil UTC. Les transferts directs ne consomment pas ce quota. Au plafond, le relais est suspendu sans supplément automatique.`;for(const id of ['download-mac','download-win']){$(id).classList.toggle('disabled-link',!active);$(id).setAttribute('aria-disabled',String(!active));$(id).tabIndex=active?0:-1;}$('no-licenses').hidden=state.licenses.length>0;const root=$('licenses');root.replaceChildren();for(const license of state.licenses){const row=el('article',undefined,'license-row');const heading=el('h3',`Poste ${license.ordinal}`);const labels={activated:'Activée',not_activated:'Non activée',disabled:'Désactivée',revoked:'Révoquée'};heading.append(el('span',!license.entitled?'Hors forfait actuel':labels[license.status]||license.status,'pill'));row.append(heading,el('p',`Ordinateur : ${license.machineName || 'Aucun appareil associé'}`));const fields=el('div',undefined,'license-fields');const name=el('input'),department=el('input');name.value=license.name||'';department.value=license.department||'';name.maxLength=department.maxLength=100;name.autocomplete=department.autocomplete='off';for(const [text,input] of [['Nom de la personne ou du poste',name],['Service',department]]){const label=el('label',text);label.append(input);fields.append(label);}row.append(fields);const actions=el('div',undefined,'button-row');const mutate=async(action,body={})=>{await api(`/api/licenses/${license.id}/${action}`,body);await refresh();message('Licence mise à jour.');};actions.append(button('Enregistrer',()=>mutate('assign',{name:name.value,department:department.value})));if(license.entitled&&license.status==='not_activated')actions.append(button('Créer le lien d’activation',async()=>{const invite=await api(`/api/licenses/${license.id}/activation`,{});$('activation-url').value=`${location.origin}/activate#${invite.token}`;$('invitation').hidden=false;$('invitation').scrollIntoView({behavior:'smooth',block:'center'});message(`Lien valable jusqu’au ${date(invite.expiresAt)}. Ne le publiez pas.`);},'primary'));if(license.status==='activated')actions.append(button('Changer d’ordinateur',async()=>{if(await confirmAction('Retirer cet ordinateur ? Ses partages seront arrêtés. Vous pourrez ensuite créer un nouveau lien pour le poste de remplacement.'))await mutate('reset');}));if(license.status==='disabled')actions.append(button('Réactiver la licence',()=>mutate('enable')));else if(license.status!=='revoked')actions.append(button('Désactiver la licence',async()=>{if(await confirmAction('Désactiver cette licence et arrêter ses partages en cours ? Vous pourrez la réactiver ultérieurement.'))await mutate('disable');}));row.append(actions);root.append(row);}}
$('auth-form').addEventListener('submit',event=>{event.preventDefault();const action=event.submitter?.value||'login';run(event.submitter||$('email'),async()=>{state=await api(`/api/account/${action}`,{email:$('email').value,password:$('password').value});$('password').value='';render();message(action==='register'?'Compte Free créé. Activez votre ordinateur depuis « Mes licences » pour utiliser vos 3 liens gratuits chaque mois.':'Vous êtes connecté.');});});
$('logout').addEventListener('click',()=>run($('logout'),async()=>{await api('/api/account/logout',{});state=null;$('activation-url').value='';$('invitation').hidden=true;render();message('Vous êtes déconnecté.');}));
$('admin-refresh').addEventListener('click',()=>run($('admin-refresh'),loadAdmin));
$('refresh').addEventListener('click',()=>run($('refresh'),refresh));for(const id of ['portal','cancel'])$(id).addEventListener('click',()=>run($(id),portal));$('copy-invitation').addEventListener('click',()=>run($('copy-invitation'),async()=>{await navigator.clipboard.writeText($('activation-url').value);message('Lien copié.');}));$('close-invitation').addEventListener('click',()=>{$('activation-url').value='';$('invitation').hidden=true;});
for(const id of ['branding-company','branding-message','branding-accent'])$(id).addEventListener('input',previewBranding);
$('branding-form').addEventListener('submit',event=>{event.preventDefault();run($('branding-save'),async()=>{
  await api('/api/account/branding',{companyName:$('branding-company').value.trim(),message:$('branding-message').value.trim(),accent:$('branding-accent').value});
  await refresh();message('Personnalisation enregistrée. Elle sera utilisée pour vos nouveaux liens de partage.');
});});
render();refresh().catch(error=>{if(error.status!==401)message('L’espace client est momentanément indisponible. Aucun paiement ne peut être effectué ici.',true);});
