/**
 * Fiche logement (TL-305) — props de `logements/info-logement/index`, construites
 * par `App\Services\Property\PropertyShowService`. Toute modification ici se
 * reporte dans le service et dans `PropertyShowPageTest`.
 *
 * Dates : `*_iso` = aaaa-mm-jj pour la logique ; les autres sont déjà au format
 * jj/mm/aaaa pour l'affichage.
 */
import type { Reservation } from '@/types';

export interface LogementShowProperty {
    id: number;
    uid: string;
    name: string;
    internal_name: string | null;
    is_active: boolean;
    /** Parties non vides jointes : « 39 rue Abou Kacem Chebbi, 2070 Tunisie ». */
    address: string;
    /** Devise du logement (« USD », « EUR », « TND »…), null si absente. */
    currency: string | null;
    /** Toutes les URL de photos, dans l'ordre du canal. */
    photos: string[];
    /** Au moins un champ des instructions d'entrée est rempli (sinon pas de lien à copier). */
    has_entry_instructions: boolean;
}

export interface LogementShowComposition {
    standard_guests: number | null;
    can_sleep_max: number | null;
    bed_double: number;
    bed_simple: number;
    bathrooms: number;
    space_m2: number | null;
    /** 0 = rez-de-chaussée. */
    floor: number | null;
}

/**
 * Type du dépôt de garantie tel que synchronisé (config/deposit-types.php) :
 * 1 none, 2 percent_without_cleaning, 3 percent_total, 4 per_night, 5 per_stay.
 */
export type LogementShowDepositType = 'none' | 'percent_without_cleaning' | 'percent_total' | 'per_night' | 'per_stay' | 'unknown';

export interface LogementShowPricing {
    nightly_price: number | null;
    cleaning_fee: number | null;
    deposit: {
        type: LogementShowDepositType;
        amount: number | null;
    };
}

export interface LogementShowStayRules {
    check_in_from: string | null;
    check_in_to: string | null;
    check_out_until: string | null;
    preparation_hours: number | null;
}

export interface LogementShowCancellationTier {
    /** Jours avant l'arrivée, bornes incluses (0 = jour d'arrivée). */
    from_days: number;
    to_days: number;
    /** Part facturée, 0–100. */
    percent: number;
}

export interface LogementShowCancellation {
    /** Triés du plus proche de l'arrivée au plus lointain. Vide = aucune politique. */
    tiers: LogementShowCancellationTier[];
    /** Annulation gratuite à partir de N jours avant l'arrivée ; null si la politique n'en prévoit pas. */
    free_from_days: number | null;
}

export interface LogementShowOccupancy {
    /** 0–100, une décimale. */
    rate: number;
    nights_booked: number;
    available_nights: number;
}

export interface LogementShowKpis {
    /** 12 mois glissants jusqu'à aujourd'hui. */
    occupancy_12m: LogementShowOccupancy;
    /** Du 1er du mois en cours à la fin du mois. */
    occupancy_month: LogementShowOccupancy;
    /** Séjours confirmés, hors séjours propriétaire, arrivés dans les 12 derniers mois. */
    stays_12m: number;
    /** Durée moyenne de ces séjours, en nuits (une décimale) ; null sans séjour. */
    avg_nights_12m: number | null;
}

export interface LogementShowStay {
    id: number;
    guest_name: string;
    check_in: string;
    check_out: string;
    check_in_iso: string;
    check_out_iso: string;
    nights: number;
    /** « Airbnb », « Booking.com », « Thelandlord.tn »… */
    source: string;
    /** HH:MM quand l'heure d'arrivée est connue. */
    arrival_time: string | null;
    /** Séjour du propriétaire dans son propre logement (bloque le calendrier, hors statistiques). */
    is_owner: boolean;
    /** Fiche du séjour, null si l'utilisateur n'y a pas accès. */
    url: string | null;
    /** Lien public des instructions d'entrée de CE séjour ; null sans instructions ou sans droit `reservation.*`. */
    instructions_url: string | null;
    /** jj/mm/aaaa : le lien s'ouvre jusqu'à 23:59 ce jour-là (lendemain du départ réel) ; null sans lien. */
    instructions_valid_until: string | null;
    /** Séjour soldé (reste à payer ≤ 0, même règle que le tableau de bord). */
    is_paid: boolean;
}

export type LogementShowTodayKind = 'arrival' | 'departure' | 'in_stay';

export interface LogementShowToday {
    date_iso: string;
    date: string;
    /** Vide = aucun mouvement aujourd'hui. Départ avant arrivée quand les deux tombent le même jour. */
    events: { kind: LogementShowTodayKind; stay: LogementShowStay }[];
}

export interface LogementShowOwner {
    /** linked = compte trouvé ; missing = aucun propriétaire saisi ; not_found = le compte lié n'existe plus. */
    status: 'linked' | 'missing' | 'not_found';
    name: string | null;
    /** Fiche du propriétaire, null sans droit `owner.update`. */
    url: string | null;
    /** Mandats de gestion (ce logement, puis ceux du propriétaire sans logement précis) ; null sans accès à l'écran des propriétaires. */
    mandates: LogementShowMandate[] | null;
    /** Création d'un mandat ; null sans accès. */
    mandate_create_url: string | null;
}

export interface LogementShowMandate {
    /** Page du contrat (nouvel onglet), comme l'icône « fichier » de l'écran des propriétaires. */
    url: string;
    status: 'signed' | 'pending';
    /** jj/mm/aaaa ; null si la date de signature n'a pas été enregistrée. */
    signed_at: string | null;
    created_at: string | null;
    /** property = mandat de ce logement ; owner = mandat du propriétaire sans logement précis. */
    scope: 'property' | 'owner';
}

export interface LogementShowListing {
    id: number;
    channel: string;
    is_active: boolean;
    url: string;
}

/**
 * Carte « Instructions d'entrée ». Null pour qui ne gère pas les séjours (les
 * instructions portent des codes d'accès et le WiFi).
 */
export interface LogementShowEntryInstructions {
    /** Rubriques remplies, dans l'ordre de la page publique : maps_url, lockbox_code, residence_code, floor, apartment_number, wifi, notes, media. Vide = rien à transmettre. */
    filled: string[];
}

/**
 * Lien de LOGEMENT vers les instructions d'entrée, valable une heure, pour
 * transmettre les accès sans réservation. Prop `Inertia::optional` créée au
 * clic (rechargement partiel) ; null sans droit ou sans instructions.
 */
export interface LogementShowEntryLink {
    url: string;
    expires_at_iso: string;
    /** HH:MM, heure du serveur. */
    expires_at: string;
}

/** Chaque lien est null quand la route le refuserait à cet utilisateur. */
export interface LogementShowLinks {
    /** `/logements/edit/{id}` — les cartes y ajoutent `?step=N`. */
    edit: string | null;
    calendar: string | null;
    planning: string | null;
    reservations: string | null;
}

/** Onglet Statistiques : séjours confirmés hors séjours propriétaire, depuis la création. Montants en TND (convertis). */
export interface LogementShowStats {
    revenue_tnd: number;
    average_price_tnd: number | null;
    average_nights: number | null;
    stay_count: number;
    occupancy_lifetime: number;
}

/**
 * Calendrier compact (accordéon « Calendrier et planning », volet ouvert
 * d'office). Prop `Inertia::defer` : absente du premier rendu, réclamée par le
 * client Inertia juste après ; null sans `calendar.view`.
 */
export type LogementShowAvailabilityKind = 'reservation' | 'ical' | 'manual_block' | 'channel_block';

export interface LogementShowAvailabilityEvent {
    kind: LogementShowAvailabilityKind;
    /** Première nuit occupée, aaaa-mm-jj. */
    start_iso: string;
    /** Dernière nuit occupée, INCLUSE (une réservation 08→11 occupe 08, 09, 10). */
    end_iso: string;
    /** Nom du voyageur pour une réservation ; null sinon. */
    label: string | null;
    /** Canal de la réservation (« Airbnb »…) ou libellé de la source iCal ; null sinon. */
    source: string | null;
    comment: string | null;
    blocked_by: string | null;
    /** Fiche du séjour, null sans droit `reservation.*`. */
    reservation_url: string | null;
}

export interface LogementShowAvailability {
    from_iso: string;
    to_iso: string;
    events: LogementShowAvailabilityEvent[];
    /** false = les disponibilités du canal n'ont pas pu être lues : seules les réservations et blocages locaux sont affichés. */
    channel_read: boolean;
}

/** Planning compact : null sans `planification.view`. */
export type LogementShowPlanningKind = 'arrival' | 'departure_cleaning' | 'mid_stay_cleaning';

export interface LogementShowPlanningEvent {
    kind: LogementShowPlanningKind;
    date_iso: string;
    guest_name: string;
    /** Ménages seulement : au moins une personne assignée. Toujours false pour une arrivée. */
    assigned: boolean;
    /** Noms des personnes assignées au ménage. */
    housekeepers: string[];
    /** Ménage vérifié (contrôle qualité). */
    verified: boolean;
}

export interface LogementShowPlanning {
    from_iso: string;
    to_iso: string;
    events: LogementShowPlanningEvent[];
}

/**
 * Ligne du tableau de l'onglet Réservations (tous statuts), servie arrivée la
 * plus récente en tête. Dates affichées jj/mm/aaaa ; le tri se fait sur les
 * `*_iso` et sur `amount_raw` — jamais sur le texte affiché.
 */
export type LogementShowReservationRow = Reservation & {
    reservation_status: string;
    payment_status: string;
    source: string;
    client_name: string;
    /** « 1 132.00 » — affichage seulement. */
    amount: string;
    amount_raw: number;
    /** aaaa-mm-jj hh:mm:ss, '' si inconnue. */
    created_iso: string;
    check_in_iso: string;
    check_out_iso: string;
};

export type LogementShowPageProps = {
    property: LogementShowProperty;
    composition: LogementShowComposition;
    pricing: LogementShowPricing;
    stay_rules: LogementShowStayRules;
    cancellation: LogementShowCancellation;
    kpis: LogementShowKpis;
    today: LogementShowToday;
    upcoming: LogementShowStay[];
    owner: LogementShowOwner;
    listings: LogementShowListing[];
    links: LogementShowLinks;
    stats: LogementShowStats;
    /** Toutes les réservations du logement, tous statuts, pour le tableau de l'onglet Réservations. */
    reservations: LogementShowReservationRow[];
    entry_instructions: LogementShowEntryInstructions | null;
    /** Absent tant qu'on n'a pas cliqué « Générer un lien » ; null sans droit ou sans instructions. */
    entry_link?: LogementShowEntryLink | null;
    /** Différée : absente au premier rendu, arrive juste après ; null sans droit. */
    availability?: LogementShowAvailability | null;
    /** Absent tant que son volet n'a pas été ouvert ; null sans droit. */
    planning?: LogementShowPlanning | null;
    flash?: { type: string; message: string };
};
