<?php
namespace App\Controllers;

use App\Core\Auth;
use App\Core\Controller;
use App\Core\Csrf;
use App\Core\Permission;
use App\Models\Billing;
use App\Models\Treasury;
use App\Services\InvoiceMailer;

final class BillingController extends Controller
{
    private function org(): int { return (int)(Auth::user()['organisation_id']??1); }
    public function index(): void { Auth::requireLogin();Permission::require('facturation.view');$this->view('billing/index',['pageTitle'=>'Facturation','invoices'=>Billing::dashboard($this->org())]); }
    public function prepared(): void { Auth::requireLogin();Permission::require('facturation.create');Billing::syncAnnualMemberships($this->org(),(int)Auth::id());$this->view('billing/prepared',['pageTitle'=>'Éléments à facturer','items'=>Billing::preparedItems($this->org()),'assignments'=>Billing::assignments($this->org())]); }
    public function syncPrepared(): void { Auth::requireLogin();Permission::require('facturation.create');Csrf::verify($_POST['_csrf']??null);try{$count=Billing::syncPrepared($this->org(),(int)Auth::id());$_SESSION['success']=$count.' nouvelle(s) inscription(s) ajoutée(s) à la préparation.';}catch(\Throwable $e){$_SESSION['form_errors']=[$e->getMessage()];}$this->redirect('/facturation/a-preparer'); }
    public function generatePrepared(): void { Auth::requireLogin();Permission::require('facturation.create');Csrf::verify($_POST['_csrf']??null);$ids=array_values(array_unique(array_filter(array_map('intval',$_POST['item_ids']??[]))));if(!$ids){$_SESSION['form_errors']=['Sélectionnez au moins une ligne à facturer.'];$this->redirect('/facturation/a-preparer');}try{$invoices=Billing::generatePrepared($this->org(),$ids,$_POST,(int)Auth::id());$_SESSION['success']=count($invoices).' brouillon(s) créé(s) ou complété(s). Les lignes d’un même adhérent sont regroupées.';}catch(\Throwable $e){$_SESSION['form_errors']=[$e->getMessage()];}$this->redirect('/facturation/a-preparer'); }
    public function cancelPrepared(): void { Auth::requireLogin();Permission::require('facturation.archive');Csrf::verify($_POST['_csrf']??null);try{Billing::cancelPreparedItem($this->org(),(int)($_POST['id']??0),(int)Auth::id());$_SESSION['success']='Élément supprimé. La demande correspondante a été annulée dans le dossier Famille.';}catch(\Throwable $e){$_SESSION['form_errors']=[$e->getMessage()];}$this->redirect('/facturation/a-preparer'); }
    public function pendingPayments(): void { Auth::requireLogin();Permission::require('facturation.accounting');$this->view('billing/pending_payments',['pageTitle'=>'Paiements à valider','invoices'=>Billing::pendingPayments($this->org())]); }
    public function validatePendingPayments(): void { Auth::requireLogin();Permission::require('facturation.accounting');Csrf::verify($_POST['_csrf']??null);$ids=array_values(array_unique(array_filter(array_map('intval',$_POST['invoice_ids']??[]))));if(!$ids){$_SESSION['form_errors']=['Sélectionnez au moins une facture.'];$this->redirect('/facturation/paiements-a-valider');}try{$count=Billing::validatePendingPayments($this->org(),$ids,(int)Auth::id());$_SESSION['success']=$count.' facture(s) validée(s) comme payée(s). La fiche adhérent et les données du portail famille ont été actualisées.';}catch(\Throwable $e){$_SESSION['form_errors']=[$e->getMessage()];}$this->redirect('/facturation/paiements-a-valider'); }
    public function mergeDrafts(): void { Auth::requireLogin();Permission::require('facturation.edit');Csrf::verify($_POST['_csrf']??null);try{$count=Billing::mergeDrafts($this->org(),(int)Auth::id());$_SESSION['success']=$count?$count.' ancien(s) brouillon(s) regroupé(s). Il ne reste qu’un brouillon par adhérent.':'Aucun brouillon en double à regrouper.';}catch(\Throwable $e){$_SESSION['form_errors']=[$e->getMessage()];}$this->redirect('/facturation'); }
    public function create(): void { Auth::requireLogin();Permission::require('facturation.create');$this->view('billing/form',['pageTitle'=>'Nouvelle facture','clients'=>Billing::clients($this->org()),'assignments'=>Billing::assignments($this->org())]); }
    public function store(): void
    {
        Auth::requireLogin();Permission::require('facturation.create');Csrf::verify($_POST['_csrf']??null);
        try{$lines=[];$descriptions=$_POST['description']??[];foreach($descriptions as $i=>$description){$description=trim((string)$description);if($description==='')continue;$assignment=(int)($_POST['assignment_id'][$i]??0);$found=null;foreach(Billing::assignments($this->org()) as $a)if((int)$a['id']===$assignment)$found=$a;if(!$found)throw new \RuntimeException('Affectation comptable invalide.');$qty=max(0.01,(float)($_POST['quantity'][$i]??1));$price=round((float)($_POST['unit_price'][$i]??0),2);$gross=round($qty*$price,2);$discount=max(0,min($gross,round((float)($_POST['discount'][$i]??0),2)));$lines[]=['description'=>$description,'assignment_id'=>$assignment,'pole_code'=>$found['pole_code']??'','project_code'=>$found['project_code']??'','account'=>$found['revenue_account'],'start'=>trim((string)($_POST['service_start'][$i]??'')),'end'=>trim((string)($_POST['service_end'][$i]??'')),'mode'=>($_POST['allocation_mode'][$i]??'current_year')==='period'?'period':'current_year','quantity'=>$qty,'unit_price'=>$price,'gross'=>$gross,'discount'=>$discount,'net'=>round($gross-$discount,2)];}if(!$lines)throw new \RuntimeException('Ajoutez au moins une ligne.');$id=Billing::create($this->org(),(int)($_POST['client_id']??0),$lines,($_POST['document_type']??'invoice')==='proforma'?'proforma':'invoice',(int)Auth::id());$_SESSION['success']='Document enregistré en brouillon.';$this->redirect('/facturation/voir?id='.$id);}catch(\Throwable $e){$_SESSION['form_errors']=[$e->getMessage()];$this->redirect('/facturation/nouvelle');}
    }
    public function show(): void { Auth::requireLogin();Permission::require('facturation.view');$invoice=Billing::find((int)($_GET['id']??0),$this->org());if(!$invoice){http_response_code(404);exit('Document introuvable.');}$this->view('billing/show',['pageTitle'=>$invoice['document_number']?:'Brouillon','invoice'=>$invoice,'settings'=>Billing::settings($this->org()),'clientAdvances'=>Treasury::advancesByClient($this->org(),(int)$invoice['client_id'])]); }
    public function edit():void{Auth::requireLogin();Permission::require('facturation.edit');$invoice=Billing::find((int)($_GET['id']??0),$this->org());if(!$invoice||$invoice['status']!=='draft'){http_response_code(404);exit('Seul un brouillon peut être modifié.');}$this->view('billing/edit',['pageTitle'=>'Modifier le brouillon','invoice'=>$invoice]);}
    public function update():void{Auth::requireLogin();Permission::require('facturation.edit');Csrf::verify($_POST['_csrf']??null);$id=(int)($_POST['id']??0);try{Billing::updateDraft($id,$this->org(),$_POST,(int)Auth::id());$_SESSION['success']='Le brouillon a été modifié.';}catch(\Throwable$e){$_SESSION['form_errors']=[$e->getMessage()];}$this->redirect('/facturation/voir?id='.$id);}
    public function deleteDraft():void{Auth::requireLogin();Permission::require('facturation.archive');Csrf::verify($_POST['_csrf']??null);try{Billing::deleteDraft($this->org(),(int)($_POST['id']??0),(int)Auth::id());$_SESSION['success']='Le brouillon a été supprimé et ses lignes sont de nouveau disponibles dans À facturer.';}catch(\Throwable$e){$_SESSION['form_errors']=[$e->getMessage()];}$this->redirect('/facturation');}
    public function issueTogether():void{Auth::requireLogin();Permission::require('facturation.create');Csrf::verify($_POST['_csrf']??null);try{$id=Billing::issueDraftsTogether($this->org(),$_POST['draft_ids']??[],(int)Auth::id());$_SESSION['success']='Les brouillons sélectionnés ont été réunis et la facture unique a été générée.';$this->redirect('/facturation/voir?id='.$id);}catch(\Throwable$e){$_SESSION['form_errors']=[$e->getMessage()];$this->redirect('/facturation');}}
    public function issue(): void { Auth::requireLogin();Permission::require('facturation.create');Csrf::verify($_POST['_csrf']??null);Billing::issue((int)$_POST['id'],$this->org());$_SESSION['success']='Document numéroté et écritures générées.';$this->redirect('/facturation/voir?id='.(int)$_POST['id']); }
    public function payment(): void { Auth::requireLogin();Permission::require('facturation.payments');Csrf::verify($_POST['_csrf']??null);Billing::payment((int)$_POST['id'],$this->org(),round((float)$_POST['amount'],2),trim((string)$_POST['method']),$_POST['payment_date']?:date('Y-m-d'),trim((string)($_POST['reference']??'')),(int)Auth::id());$this->redirect('/facturation/voir?id='.(int)$_POST['id']); }
    public function bank(): void { Auth::requireLogin();Permission::require('facturation.payments');Csrf::verify($_POST['_csrf']??null);Billing::bank((int)$_POST['payment_id'],$this->org());$this->redirect('/facturation/voir?id='.(int)$_POST['id']); }
    public function credit(): void { Auth::requireLogin();Permission::require('facturation.credit');Csrf::verify($_POST['_csrf']??null);$source=Billing::find((int)$_POST['id'],$this->org());if(!$source||$source['document_type']!=='invoice')exit('Facture source invalide.');$lines=[];foreach($source['lines'] as $l)$lines[]=['description'=>'Avoir — '.$l['description'],'assignment_id'=>$l['assignment_id'],'pole_code'=>$l['pole_code'],'project_code'=>$l['project_code'],'account'=>$l['revenue_account'],'start'=>$l['service_start'],'end'=>$l['service_end'],'mode'=>$l['allocation_mode'],'quantity'=>$l['quantity'],'unit_price'=>$l['unit_price'],'gross'=>$l['gross_amount'],'discount'=>$l['discount_amount'],'net'=>$l['net_amount'],'source_line_id'=>$l['id']];$id=Billing::create($this->org(),(int)$source['client_id'],$lines,'credit',(int)Auth::id(),(int)$source['id']);Billing::issue($id,$this->org());$this->redirect('/facturation/voir?id='.$id); }
    public function print(): void { Auth::requireLogin();Permission::require('facturation.view');$invoice=Billing::find((int)($_GET['id']??0),$this->org());if(!$invoice)exit('Document introuvable.');$settings=Billing::settings($this->org());require BASE_PATH.'/app/Views/billing/print.php'; }
    public function email(): void { Auth::requireLogin();Permission::require('facturation.create');Csrf::verify($_POST['_csrf']??null);$invoice=Billing::find((int)$_POST['id'],$this->org());if(!$invoice)exit('Document introuvable.');InvoiceMailer::send($invoice,Billing::settings($this->org()),(int)Auth::id());$this->redirect('/facturation/voir?id='.(int)$_POST['id']); }
    public function csv(): void { Auth::requireLogin();Permission::require('facturation.accounting');$i=Billing::find((int)($_GET['id']??0),$this->org());if(!$i)exit('Document introuvable.');header('Content-Type: text/csv; charset=UTF-8');header('Content-Disposition: attachment; filename="ecritures-'.($i['document_number']?:$i['id']).'.csv"');echo "\xEF\xBB\xBFDate;Journal;Compte;Libellé;Débit;Crédit\r\n";foreach($i['entries'] as $e)echo implode(';',[$e['entry_date'],$e['journal_code'],$e['account_number'],str_replace(';',',',$e['label']),number_format((float)$e['debit'],2,',',''),number_format((float)$e['credit'],2,',','')])."\r\n";exit; }
    public function settings(): void { Auth::requireLogin();Permission::require('facturation.settings');$this->view('billing/settings',['pageTitle'=>'Paramètres de facturation','settings'=>Billing::settings($this->org()),'assignments'=>Billing::assignments($this->org(),false)]); }
    public function saveSettings(): void { Auth::requireLogin();Permission::require('facturation.settings');Csrf::verify($_POST['_csrf']??null);Billing::saveSettings($this->org(),$_POST);$this->redirect('/facturation/parametres'); }
    public function assignment(): void { Auth::requireLogin();Permission::require('facturation.settings');Csrf::verify($_POST['_csrf']??null);Billing::saveAssignment($this->org(),$_POST);$this->redirect('/facturation/parametres'); }
}
