import { DateTime } from 'luxon'
import db from '@adonisjs/lucid/services/db'
import Organization from '#models/organization'

/**
 * Politique de plans Rubis V1 :
 *
 *  - Free      : 5 factures actives en relance, 1 user
 *  - Pro       : factures illimitées, 1 user
 *  - Business  : factures illimitées, 5 users (V2 multi-users), réponses
 *                par l'adresse mail user (V2 enhancement)
 *
 * Période de grâce : à l'inscription, l'org démarre en `free` avec un
 * `gracePeriodEndsAt = createdAt + 3 mois`. Pendant cette fenêtre, AUCUNE
 * limite n'est appliquée — l'user peut tester full power. Au-delà des 3
 * mois, si `activeInvoicesCount > 5` → import bloqué jusqu'à upgrade.
 */

export type PlanKey = 'free' | 'pro' | 'business'

export type PlanCaps = {
  /** Nombre max de factures dans un état "actif" (pending / awaiting / in_relance / litigation). null = illimité. */
  activeInvoicesLimit: number | null
  /** Nombre max d'utilisateurs par org. null = illimité. */
  seatsLimit: number | null
  /** Multi-users autorisé ? V1 : seulement Business (mais pas implémenté). */
  multiUsers: boolean
  /** Réponse via l'email du user au lieu d'un from-Rubis générique ? V2. */
  replyFromUserEmail: boolean
  /** SMS V2. */
  smsEnabled: boolean
}

export const PLAN_CAPS: Record<PlanKey, PlanCaps> = {
  free: {
    activeInvoicesLimit: 5,
    seatsLimit: 1,
    multiUsers: false,
    replyFromUserEmail: false,
    smsEnabled: false,
  },
  pro: {
    activeInvoicesLimit: null,
    seatsLimit: 1,
    multiUsers: false,
    replyFromUserEmail: false,
    smsEnabled: false,
  },
  business: {
    activeInvoicesLimit: null,
    seatsLimit: 5,
    multiUsers: true,
    replyFromUserEmail: true,
    smsEnabled: false, // V2
  },
}

const ACTIVE_STATUSES = ['pending', 'awaiting_user_confirmation', 'in_relance', 'litigation']

/**
 * Compte les factures considérées "actives" pour la limite Free :
 * statut ∈ {pending, awaiting_user_confirmation, in_relance, litigation}.
 * paid / cancelled n'occupent pas de slot.
 */
export async function countActiveInvoices(organizationId: string): Promise<number> {
  const row = await db
    .from('invoices')
    .where('organization_id', organizationId)
    .whereIn('status', ACTIVE_STATUSES)
    .count('* as n')
    .first()
  return Number(row?.n ?? 0)
}

export type EnforcementResult =
  | { allowed: true }
  | {
      allowed: false
      reason: 'free_limit_active_invoices'
      limit: number
      current: number
      gracePeriodEndsAt: string | null
    }

/**
 * Vérifie si l'org peut créer N nouvelles factures actives.
 *
 * Règle :
 *  - Plans payants → toujours autorisé
 *  - Free pendant la période de grâce → autorisé sans limite
 *  - Free après période de grâce → bloque si `current + delta > limit`
 *
 * `delta` = nombre de factures qu'on s'apprête à créer (typiquement 1
 * pour saisie manuelle, N pour upload OCR multi-fichiers).
 */
export async function canCreateInvoices(
  organizationId: string,
  delta = 1
): Promise<EnforcementResult> {
  const org = await Organization.find(organizationId)
  if (!org) return { allowed: true } // org introuvable → pas notre rôle de bloquer ici

  const plan = (org.plan ?? 'free') as PlanKey
  const caps = PLAN_CAPS[plan]
  if (caps.activeInvoicesLimit === null) return { allowed: true }

  // Free + dans la période de grâce → unlimited
  const now = DateTime.utc()
  if (org.gracePeriodEndsAt && org.gracePeriodEndsAt > now) {
    return { allowed: true }
  }

  const current = await countActiveInvoices(organizationId)
  if (current + delta <= caps.activeInvoicesLimit) {
    return { allowed: true }
  }

  return {
    allowed: false,
    reason: 'free_limit_active_invoices',
    limit: caps.activeInvoicesLimit,
    current,
    gracePeriodEndsAt: org.gracePeriodEndsAt?.toISO() ?? null,
  }
}

/**
 * État subscription de l'org pour exposition côté SPA — utilisé par la
 * page /parametres/abonnement.
 */
export type OrgSubscriptionState = {
  plan: PlanKey
  caps: PlanCaps
  /** Compteur courant de factures actives. */
  activeInvoicesCount: number
  /** True tant que l'org bénéficie de la fenêtre 3 mois post-signup. */
  inGracePeriod: boolean
  gracePeriodEndsAt: string | null
  /** Status Stripe (`active`, `trialing`, `past_due`, `canceled`...). null pour les Free. */
  subscriptionStatus: string | null
  /** 'monthly' | 'yearly' | null pour les Free. */
  billingCycle: 'monthly' | 'yearly' | null
  /** ISO date de fin de période courante (= prochaine facture Stripe). */
  currentPeriodEnd: string | null
  /** True si l'org a un Stripe customer ID (= a déjà payé une fois). */
  hasStripeCustomer: boolean
  /**
   * True si l'user a annulé sa souscription côté Stripe et qu'elle s'éteindra
   * à `currentPeriodEnd`. Pendant cette fenêtre l'org reste sur son plan
   * payant (status `active`), mais l'UI affiche "annulé, accès jusqu'au DD/MM"
   * et propose un bouton "Réactiver".
   */
  cancelAtPeriodEnd: boolean
}

export async function getOrgSubscriptionState(
  organizationId: string
): Promise<OrgSubscriptionState> {
  const org = await Organization.findOrFail(organizationId)
  const plan = (org.plan ?? 'free') as PlanKey
  const now = DateTime.utc()
  const inGracePeriod =
    plan === 'free' && !!org.gracePeriodEndsAt && org.gracePeriodEndsAt > now

  return {
    plan,
    caps: PLAN_CAPS[plan],
    activeInvoicesCount: await countActiveInvoices(organizationId),
    inGracePeriod,
    gracePeriodEndsAt: org.gracePeriodEndsAt?.toISO() ?? null,
    subscriptionStatus: org.subscriptionStatus ?? null,
    billingCycle:
      org.billingCycle === 'monthly' || org.billingCycle === 'yearly'
        ? org.billingCycle
        : null,
    currentPeriodEnd: org.currentPeriodEnd?.toISO() ?? null,
    hasStripeCustomer: !!org.stripeCustomerId,
    cancelAtPeriodEnd: !!org.cancelAtPeriodEnd,
  }
}
