module Billing
  # Etichette leggibili per lo storico pagamenti (mai testo grezzo Stripe / webhook).
  class PaymentDescription
    UGLY = /\A(webhook\s*test|test|x|—|-)\z/i

    AMOUNT_HINTS = {
      500 => %w[premium_light monthly],
      4000 => %w[premium_light yearly],
      2000 => %w[premium_full monthly],
      20_000 => %w[premium_full yearly]
    }.freeze

    class << self
      def for_stripe_invoice(invoice)
        plan_slug, interval = extract_plan_and_interval(invoice)
        build(plan_slug: plan_slug, interval: interval, amount_cents: invoice.amount_paid)
      end

      def for_payment(payment)
        stored = payment.description.to_s.strip
        return stored if stored.present? && !ugly?(stored)

        build(
          plan_slug: payment.plan_slug,
          interval: nil,
          amount_cents: payment.amount_cents
        )
      end

      private

      def build(plan_slug:, interval:, amount_cents:)
        plan_slug, interval = resolve_plan_interval(plan_slug, interval, amount_cents)
        return plan_label(plan_slug, interval) if plan_slug.present?

        if amount_cents.present? && amount_cents.to_i.positive?
          euros = format("%.2f", amount_cents.to_i / 100.0)
          return "Pagamento Match Live TV — #{euros} €"
        end

        "Abbonamento Match Live TV"
      end

      def resolve_plan_interval(plan_slug, interval, amount_cents)
        plan_slug = plan_slug.presence
        interval = interval.presence

        if plan_slug.blank? && amount_cents.present?
          hint = AMOUNT_HINTS[amount_cents.to_i]
          plan_slug, interval = hint if hint
        end

        if plan_slug.present? && interval.blank? && amount_cents.present?
          hint = AMOUNT_HINTS[amount_cents.to_i]
          interval = hint&.last if hint&.first == plan_slug
        end

        interval ||= Billing::Stripe::PriceCatalog::DEFAULT_INTERVAL if plan_slug.present?
        [plan_slug, interval]
      end

      def plan_label(plan_slug, interval)
        plan = Plan[plan_slug]
        price = Billing::Stripe::PriceCatalog.label(plan_slug: plan_slug, interval: interval)
        "#{plan.name} — #{price}"
      rescue KeyError
        plan_slug.to_s.humanize
      end

      def extract_plan_and_interval(invoice)
        meta = merged_metadata(invoice)
        plan_slug = meta["plan_slug"].presence
        interval = normalize_interval(meta["billing_interval"])

        line = invoice.lines&.data&.first
        if line
          line_meta = line_metadata(line)
          plan_slug ||= line_meta["plan_slug"]
          interval ||= normalize_interval(line_meta["billing_interval"])

          price_id = line_price_id(line)
          from_price = Billing::Stripe::PriceCatalog.infer_from_price_id(price_id)
          plan_slug ||= from_price&.first
          interval ||= from_price&.last
        end

        plan_slug = normalize_plan_slug(plan_slug)
        [plan_slug, interval]
      end

      def merged_metadata(invoice)
        Billing::Stripe::InvoiceMetadata.merged(invoice)
      end

      def line_metadata(line)
        meta = Billing::Stripe::InvoicePaymentRefs.safe_get(line, :metadata)
        meta.to_h.stringify_keys
      rescue NoMethodError
        {}
      end

      def line_price_id(line)
        pricing = Billing::Stripe::InvoicePaymentRefs.safe_get(line, :pricing)
        details = Billing::Stripe::InvoicePaymentRefs.safe_get(pricing, :price_details)
        Billing::Stripe::InvoicePaymentRefs.safe_get(details, :price)
      end

      def normalize_interval(value)
        return nil if value.blank?

        Billing::Stripe::PriceCatalog.normalize_interval(value)
      rescue ArgumentError
        nil
      end

      def normalize_plan_slug(slug)
        return nil if slug.blank?

        slug = slug.to_s
        slug = "premium_full" if slug == "premium"
        slug.presence_in(%w[premium_light premium_full])
      end

      def ugly?(text)
        UGLY.match?(text.to_s.strip)
      end
    end
  end
end
