export type StatutDeclaration = 'brouillon' | 'cloturee' | 'declaree';
export type TypeBeneficiaire = 'proprietaire' | 'fournisseur';
export type TypePersonne = 'physique' | 'morale';
export type StatutPaiement = 'tous' | 'paye' | 'non_paye';

export interface Totaux {
    brut: number;
    retenue: number;
    net: number;
    count: number;
}

export interface RetenueDeclaration {
    id: number;
    annee: number;
    mois: number;
    libelle_periode: string; // « Janvier 2026 »
    periode_debut: string; // YYYY-MM-DD
    periode_fin: string; // YYYY-MM-DD
    statut: StatutDeclaration;
    is_locked: boolean; // montants/taux figés (clôturée ou déclarée)
    is_declaree: boolean;
    /** Lignes sans certificat chez la DGI — c'est lui qui décide du bouton « Déposer ». */
    reste_a_deposer: number; // même le paiement est figé
    cloturee_at: string | null;
    declaree_at: string | null;
    tej_reference: string | null;
    total_brut: number | null; // figés à la clôture, null en brouillon
    total_retenue: number | null;
    total_net: number | null;
}

export interface RetenueLigne {
    id: number;
    declaration_id: number;
    beneficiaire_type: TypeBeneficiaire;
    /** Ligne de `beneficiaires` — fournisseur ou propriétaire, la table est unique. */
    beneficiaire_id: number | null;
    property_id: number | null;
    property_nom: string | null;

    beneficiaire_nom: string;
    beneficiaire_matricule_fiscal: string | null;
    beneficiaire_cin: string | null;
    beneficiaire_type_personne: TypePersonne | null;

    /** Référence : revenu du logement pour un propriétaire, montant d'origine sinon. */
    montant_brut_calcule: number;
    /** Ce qui est déclaré. Différent de `montant_brut_calcule` ⇒ saisie manuelle. */
    montant_brut: number;

    /** Taux figé sur la ligne — c'est lui qui fait foi, plus aucun catalogue. */
    taux: number;
    taux_libelle: string | null;
    montant_retenue: number;
    montant_net: number;

    est_paye: boolean;
    date_paiement: string | null; // YYYY-MM-DD
    mode_paiement: string | null;
    banque: string | null;
    reference_paiement: string | null;
    libelle_paiement: string | null; // « VT UIB LE 12/02/2026 »

    facture_numero: string | null;
    facture_date: string | null;

    note: string | null;
    identite_complete: boolean; // pilote le badge d'avertissement

    /** Numéro du certificat chez TEJ — nul tant que le mois n'est pas déposé. */
    tej_reference: string | null;

    // --- Décomposition et champs exigés par le fichier de dépôt ---
    /** Base hors taxe. Avec `taux_tva`, elle détermine le TTC (= `montant_brut`). */
    montant_ht: number;
    taux_tva: number;
    montant_tva: number;
    /** Code de la nomenclature TEJ (`RS7_000002`) → attribut `IdTypeOperation`. */
    tej_operation_code: string | null;
    /** Exercice de facturation/exigibilité → balise `AnneeFacturation`. */
    annee_facturation: number | null;
    /** Convention de non double imposition → balise `CNPC`. */
    cnpc: boolean;
    /** Retenue prise en charge par le payeur → balise `P_Charge`. */
    prise_en_charge: boolean;
    /**
     * Non nul ⇒ le certificat EXISTE chez TEJ. La ligne n'est plus déposable :
     * la redéposer la compterait deux fois, et la plateforme ne refuse pas les
     * doublons.
     */
    tej_uuid: string | null;
    tej_statut: string | null;
}

/** Opération de la nomenclature TEJ, remplie par `tej:sync-referentiels`. */
export interface OperationTejOption {
    code: string;
    label: string;
    /** Type d'opération — sert de groupe dans le sélecteur. */
    groupe: string;
    /** Indicatif : le taux qui fait foi est imposé par TEJ à la saisie. */
    taux: number | null;
}

/**
 * Taux proposé à la saisie.
 *
 * Vient de `config('retenue.taux')` — il n'existe plus de table
 * `retenue_taux`, donc plus d'`id` : la clé est le `code`. Une ligne déjà
 * enregistrée ne porte que `taux` + `taux_libelle` ; ce catalogue n'est qu'une
 * liste de raccourcis de saisie.
 */
export interface TauxOption {
    code: string;
    libelle: string;
    taux: number;
    seuil_min_ttc: number | null;
}

/** Bénéficiaire sélectionnable — ligne de `beneficiaires` sans `user_id`. */
export interface BeneficiaireOption {
    id: number;
    raison_sociale: string;
    matricule_fiscal: string | null;
    cin: string | null;
    type_personne: TypePersonne;
}

/**
 * Propriétaire du parc — RÉEXPORTÉ depuis /fournisseurs, jamais redéclaré.
 *
 * Les deux écrans reçoivent la MÊME liste, construite une seule fois par
 * `RetenueLigneService::optionsProprietaires()`. Deux interfaces parallèles
 * auraient divergé au premier champ ajouté d'un seul côté — c'est exactement ce
 * qui a produit deux formulaires dont un seul savait corriger une identité.
 */
import type { OwnerOption } from '../fournisseurs/owner-fiche-dialog';

export type { OwnerOption };

/**
 * Une ligne que le DÉPÔT refuserait, et la raison — dans les mots du dépôt.
 *
 * Remplace `IdentiteIncomplete`, qui ne portait qu'un nom et laissait deviner
 * ce qui manquait. Le serveur produit cette liste en construisant réellement le
 * certificat de chaque ligne : les raisons affichées ici sont mot pour mot
 * celles que le dépôt rendrait, jamais des reformulations qui pourraient
 * diverger.
 */
export interface LigneNonDeposable {
    ligne_id: number;
    beneficiaire_id: number | null;
    beneficiaire_nom: string | null;
    property_nom: string | null;
    /**
     * TOUTES les phrases de refus, telles que le dépôt les rendrait.
     *
     * Un tableau, et pas une chaîne : le dépôt s'arrête au premier manque —
     * c'est ce qu'il doit faire — mais n'en montrer qu'un à l'écran imposait de
     * corriger, relancer, découvrir le suivant, recommencer. Le serveur les
     * collecte tous en une passe.
     */
    raisons: string[];
    /**
     * OÙ ça se corrige — et ce n'est pas devinable, c'est tout l'intérêt :
     * `fiche` = l'identité du bénéficiaire (adresse, e-mail, téléphone) ;
     * `ligne` = la saisie de la déclaration (opération TEJ, exercice, montants).
     */
    ou: 'fiche' | 'ligne';
    /** Non nul ⇒ la fiche est celle d'un propriétaire du parc. */
    owner_user_id?: number | null;
}

/** Rapport du bouton « Vérifier » — lecture seule, calculé à la demande. */
export interface LogementOublie {
    property_id: number;
    property_uid: string | null;
    property_nom: string | null;
    owner_user_id: number;
    beneficiaire_nom: string;
    montant_calcule: number;
    identite_complete: boolean;
}

/** Ligne dont le montant déclaré s'écarte du montant calculé. */
export interface EcartMontant {
    ligne_id: number;
    property_nom: string | null;
    beneficiaire_nom: string;
    montant_saisi: number;
    montant_calcule: number;
    ecart: number;
}

export interface AnomalieLigne {
    ligne_id: number;
    beneficiaire_id?: number | null;
    /** Renseigné quand le bénéficiaire est un propriétaire : sa fiche est dans /owners. */
    owner_user_id?: number | null;
    beneficiaire_nom: string;
    property_nom: string | null;
}

export interface RetenueVerification {
    logements_oublies: LogementOublie[];
    ecarts: EcartMontant[];
    lignes_non_deposables: LigneNonDeposable[];
    montants_nuls: AnomalieLigne[];
    logements_sans_proprietaire: number;
    total_oublie: number;
    rien_a_signaler: boolean;
}

export interface RetenueFilters {
    mois: string; // YYYY-MM
    beneficiaire: TypeBeneficiaire | null;
    statut_paiement: StatutPaiement;
    search: string;
}

export interface RetenueCan {
    update: boolean;
    delete: boolean;
    cloture: boolean;
    declare: boolean;
    certificat: boolean;
}

export interface RetenuePageProps {
    declaration: RetenueDeclaration | null; // null si le mois n'est pas encore ouvert
    lignesProprietaires: RetenueLigne[];
    lignesFournisseurs: RetenueLigne[];
    totaux: { proprietaires: Totaux; fournisseurs: Totaux; global: Totaux };
    taux: TauxOption[];
    operationsTej: OperationTejOption[];
    fournisseurs: BeneficiaireOption[];
    proprietaires: OwnerOption[];
    filters: RetenueFilters;
    avertissements: {
        lignes_non_deposables: LigneNonDeposable[];
        logements_sans_proprietaire: number;
    };
    can: RetenueCan;
    /**
     * Prop Inertia « optional » : absente tant que le bouton « Vérifier » n'a
     * pas déclenché un rechargement partiel (le contrôle recalcule le revenu de
     * chaque logement, trop coûteux pour chaque affichage de page).
     */
    verification?: RetenueVerification | null;
}
