/**
 * Journal d'activité (TL-293) — contrat des props Inertia de `activity/index`.
 *
 * Source de vérité PARTAGÉE entre le serveur (ActivityLogController +
 * App\Services\Activity\*) et la page React. Toute clé ajoutée d'un côté
 * doit l'être ici d'abord.
 *
 * Une LIGNE du flux (ActivityEntry) regroupe une ou plusieurs lignes d'audit
 * (ActivityRecord) écrites par le même acteur, depuis la même URL, à ≤ 2 s
 * d'intervalle : un clic humain = une ligne, même quand il touche 3 tables.
 */

/** `exported` : quelqu'un a téléchargé un export CSV du journal (phase 3 — la sortie de données se trace aussi). */
export type ActivityEvent = 'created' | 'updated' | 'deleted' | 'restored' | 'login' | 'logout' | 'login_failed' | 'permissions_updated' | 'exported';

export type ActivityModule = 'reservations' | 'logements' | 'clients' | 'finances' | 'crm' | 'equipe' | 'parametres' | 'connexions' | 'autre';

/** web | webhook | sync | console | admin-report | admin-restore | admin-force */
export type ActivitySource = string;

export interface ActivityActor {
    /** null = action automatique (synchronisation, commande, webhook sans utilisateur). */
    id: number | null;
    name: string;
    /** Rôles Spatie au moment de l'action, déjà traduits et joints (« Admin, Directeur »). */
    role: string | null;
    initials: string;
    is_system: boolean;
    /**
     * Équipe de l'acteur quand elle diffère de celle du lecteur (TL-293 phase 4) :
     * « Siège » pour un membre du siège vu par une franchise, nom de la franchise
     * pour un membre de franchise vu par le siège. null = même équipe, ou système.
     */
    team: string | null;
}

/** Élément parent d'une ligne (la réservation d'une planification, d'une prolongation, d'un paiement). */
export interface ActivityParent {
    type_label: string;
    label: string;
    url: string | null;
}

/**
 * Aperçu lisible DANS la ligne du flux, sans ouvrir le panneau.
 *  - change : la première modification visible (« Statut : Confirmée → Annulée »), `more` = autres champs modifiés ;
 *  - values : les valeurs clés d'une création ou d'une suppression, déjà jointes
 *    (« A15 Malaga · 27/11 → 30/11/2026 · 116,00 TND »).
 */
export type ActivityPreview =
    | { kind: 'change'; label: string; old: string | null; new: string | null; more: number }
    | { kind: 'values'; text: string };

export interface ActivitySubject {
    /** Nom court de la classe : 'Reservation', 'Property', 'User'… */
    type: string;
    /** « Réservation », « Logement »… (majuscule, sans article). */
    type_label: string;
    /** Même chose AVEC article, pour la phrase : « la réservation », « le logement ». */
    type_phrase: string;
    id: number;
    /** Libellé humain (« #1788787164 · Ghazi Ben Hadj Yahia »), null si introuvable. */
    label: string | null;
    /** Lien vers l'élément, null si aucune page ou si l'élément n'existe plus. */
    url: string | null;
    /** L'élément a été supprimé depuis (ou par cette action). */
    deleted: boolean;
    /** Réservation parente (planification, prolongation, paiement…), null sinon. */
    parent: ActivityParent | null;
}

export interface ActivityChange {
    field: string;
    /** Libellé traduit (« Arrivée », « Statut »). */
    label: string;
    /** Valeurs DÉJÀ formatées côté serveur (jj/mm/aaaa, « 450,00 TND », « Oui »). null = vide. */
    old: string | null;
    new: string | null;
    /** Champ technique (horodatages, blobs JSON, drapeaux internes) : replié par défaut. */
    technical: boolean;
}

export interface ActivityRecord {
    id: number;
    event: ActivityEvent;
    module: ActivityModule;
    subject: ActivitySubject;
    changes: ActivityChange[];
}

export interface ActivityEntry {
    /** id de la ligne d'audit principale (la plus ancienne du groupe). */
    id: number;
    event: ActivityEvent;
    module: ActivityModule;
    actor: ActivityActor;
    subject: ActivitySubject;
    /** Libellés des champs NON techniques modifiés (≤ 4), pour les pastilles du flux. */
    summary_fields: string[];
    /** Nombre total de champs non techniques modifiés (pour « +3 »). */
    summary_count: number;
    /** Ce que la ligne affiche à la place des seuls noms de champs (phase 1). null = rien de lisible. */
    preview: ActivityPreview | null;
    /** ISO 8601 avec décalage (« 2026-09-23T14:02:11+01:00 »). */
    created_at: string;
    source: ActivitySource;
    context: {
        url: string | null;
        ip: string | null;
        /** « Chrome · Windows », « Safari · iPhone », null si inconnu. */
        device: string | null;
    };
    /** Toutes les lignes d'audit du groupe, la principale en premier. */
    records: ActivityRecord[];
}

export interface ActivityFilters {
    tab: 'feed' | 'team';
    user: string | null;
    module: ActivityModule | null;
    event: ActivityEvent | null;
    /** Dates ISO aaaa-mm-jj (bornes incluses). */
    from: string;
    to: string;
    search: string | null;
    /** Inclure les actions automatiques (siège uniquement ; toujours false en franchise). */
    system: boolean;
    /** Filtre franchise (siège uniquement) : id du compte co-host, ou 'hq' pour le siège. */
    franchise: string | null;
    /** Un seul élément : « Reservation:15509 », « Property:373 », « Client:883 », « User:41 » (phase 2). */
    subject: string | null;
    /** Seulement les gestes sensibles : suppressions, droits modifiés, échecs de connexion (phase 3). */
    sensitive: boolean;
}

export interface ActivityKpis {
    /** Actions humaines sur la période filtrée. */
    human_actions: number;
    /** Membres ayant agi au moins une fois sur la période. */
    active_members: number;
    /** Taille de l'équipe visible (dénominateur de active_members). */
    team_size: number;
    deletions: number;
    /** Actions automatiques sur la période — null hors siège (non affiché). */
    automatic: number | null;
}

export interface ActivityOption {
    id: string;
    name: string;
}

/**
 * actif < 24 h · calme 1–7 j · inactif > 7 j (a déjà agi, s'est arrêté) ·
 * never = aucune trace (ni action ni connexion) depuis le début du suivi.
 */
export type ActivityTeamState = 'active' | 'quiet' | 'inactive' | 'never';

export interface ActivityTeamRow {
    id: number;
    name: string;
    role: string | null;
    initials: string;
    /** Nom de la franchise (siège uniquement), null = siège. */
    franchise: string | null;
    /** ISO 8601 ou null (jamais vu depuis le début du suivi). */
    last_login_at: string | null;
    last_action_at: string | null;
    actions_in_range: number;
    /** actif < 24 h · calme 1–7 j · inactif > 7 j ou jamais (sur la dernière ACTION). */
    state: ActivityTeamState;
}

export interface ActivityPaginator {
    data: ActivityEntry[];
    current_page: number;
    next_page_url: string | null;
    prev_page_url: string | null;
}

/**
 * Compteurs des onglets de module au-dessus du flux. MÊMES filtres que le flux
 * (période, membre, action, recherche, franchise, actions automatiques) SAUF le
 * module, et MÊME définition d'une ligne (regroupement d'un clic) : `all` est
 * le nombre de lignes du flux quand l'onglet « Tout » est actif.
 */
export interface ActivityModuleCounts {
    all: number;
    /** Modules absents = 0. */
    by_module: Partial<Record<ActivityModule, number>>;
}

export interface ActivityPageProps {
    entries: ActivityPaginator;
    filters: ActivityFilters;
    kpis: ActivityKpis;
    /** Rempli seulement quand filters.tab === 'feed', sinon null. */
    module_counts: ActivityModuleCounts | null;
    options: {
        users: ActivityOption[];
        modules: ActivityOption[];
        events: ActivityOption[];
        /** null hors siège. */
        franchises: ActivityOption[] | null;
    };
    /** Rempli seulement quand filters.tab === 'team', sinon null. */
    team: ActivityTeamRow[] | null;
    /**
     * Historique complet de l'élément d'une ligne (panneau de détail).
     * Prop OPTIONNELLE (Inertia::optional) : chargée par
     * router.reload({ only: ['history'], data: { history: <entry.id> } }).
     */
    history?: ActivityEntry[] | null;
    /** Premières dates de suivi, pour un affichage honnête (« suivi depuis le … »). ISO ou null. */
    tracking_since: {
        audits: string | null;
        logins: string | null;
    };
    is_headquarters: boolean;
    /** Libellé de l'élément filtré (pastille « Élément : … »), null sans filtre `subject` (phase 2). */
    subject_info: ActivityParent | null;
    /**
     * Le lecteur peut exporter (bouton « Exporter », phase 3). Depuis le 25/09/2026 le journal
     * et son export sont réservés au compte TLL master (role:tll-master) : vrai pour lui seul.
     */
    can_export: boolean;
}
