require "test_helper"

class Account::SubscriptionTest < ActiveSupport::TestCase
  test "get the account plan" do
    subscription = Account::Subscription.new(plan_key: "free_v1")
    assert_equal Plan[:free_v1], subscription.plan
  end

  test "check if account is active" do
    subscription = Account::Subscription.new(status: "active")
    assert subscription.active?
  end

  test "check if account is paid" do
    assert Account::Subscription.new(plan_key: "monthly_v1", status: "active").paid?
    assert_not Account::Subscription.new(plan_key: "free_v1", status: "active").paid?
  end

  test "paid scope includes active paid subscriptions" do
    subscription = Account::Subscription.create!(
      account: accounts(:initech), plan_key: "monthly_v1", status: "active",
      stripe_customer_id: "cus_paid"
    )

    assert_includes Account::Subscription.paid, subscription
  end

  test "paid scope includes trialing and past_due subscriptions" do
    trialing = Account::Subscription.create!(
      account: accounts(:initech), plan_key: "monthly_v1", status: "trialing",
      stripe_customer_id: "cus_trialing"
    )
    past_due = Account::Subscription.create!(
      account: accounts(:acme), plan_key: "monthly_extra_storage_v1", status: "past_due",
      stripe_customer_id: "cus_past_due"
    )

    assert_includes Account::Subscription.paid, trialing
    assert_includes Account::Subscription.paid, past_due
  end

  test "paid scope excludes free plan subscriptions" do
    subscription = Account::Subscription.create!(
      account: accounts(:initech), plan_key: "free_v1", status: "active",
      stripe_customer_id: "cus_free"
    )

    assert_not_includes Account::Subscription.paid, subscription
  end

  test "paid scope excludes canceled subscriptions" do
    subscription = Account::Subscription.create!(
      account: accounts(:initech), plan_key: "monthly_v1", status: "canceled",
      stripe_customer_id: "cus_canceled"
    )

    assert_not_includes Account::Subscription.paid, subscription
  end

  test "paid scope excludes comped accounts" do
    subscription = Account::Subscription.create!(
      account: accounts(:initech), plan_key: "monthly_v1", status: "active",
      stripe_customer_id: "cus_comped"
    )
    Account::BillingWaiver.create!(account: accounts(:initech))

    assert_not_includes Account::Subscription.paid, subscription
  end

  test "pause pauses Stripe subscription with void behavior" do
    subscription = Account::Subscription.new(stripe_subscription_id: "sub_123")

    Stripe::Subscription.expects(:update).with(
      "sub_123",
      pause_collection: { behavior: "void" }
    ).returns(true)

    subscription.pause
  end

  test "pause does nothing when no stripe_subscription_id" do
    subscription = Account::Subscription.new(stripe_subscription_id: nil)

    Stripe::Subscription.expects(:update).never

    subscription.pause
  end

  test "pause raises on Stripe errors" do
    subscription = Account::Subscription.new(stripe_subscription_id: "sub_123")

    Stripe::Subscription.stubs(:update).raises(
      Stripe::APIConnectionError.new("Network error")
    )

    assert_raises Stripe::APIConnectionError do
      subscription.pause
    end
  end

  test "resume resumes Stripe subscription" do
    subscription = Account::Subscription.new(stripe_subscription_id: "sub_123")

    Stripe::Subscription.expects(:update).with(
      "sub_123",
      pause_collection: ""
    ).returns(true)

    subscription.resume
  end

  test "resume does nothing when no stripe_subscription_id" do
    subscription = Account::Subscription.new(stripe_subscription_id: nil)

    Stripe::Subscription.expects(:update).never

    subscription.resume
  end

  test "resume raises on Stripe errors" do
    subscription = Account::Subscription.new(stripe_subscription_id: "sub_123")

    Stripe::Subscription.stubs(:update).raises(
      Stripe::AuthenticationError.new("Invalid API key")
    )

    assert_raises Stripe::AuthenticationError do
      subscription.resume
    end
  end

  test "cancel cancels Stripe subscription" do
    subscription = Account::Subscription.new(stripe_subscription_id: "sub_123")

    Stripe::Subscription.expects(:cancel).with("sub_123").returns(true)

    subscription.cancel
  end

  test "cancel does nothing when no stripe_subscription_id" do
    subscription = Account::Subscription.new(stripe_subscription_id: nil)

    Stripe::Subscription.expects(:cancel).never

    subscription.cancel
  end

  test "cancel treats 404 as success" do
    subscription = Account::Subscription.new(stripe_subscription_id: "sub_deleted")

    Stripe::Subscription.stubs(:cancel).raises(
      Stripe::InvalidRequestError.new("No such subscription", {})
    )

    assert_nothing_raised do
      subscription.cancel
    end
  end

  test "cancel raises on other Stripe errors" do
    subscription = Account::Subscription.new(stripe_subscription_id: "sub_123")

    Stripe::Subscription.stubs(:cancel).raises(
      Stripe::RateLimitError.new("Rate limit exceeded")
    )

    assert_raises Stripe::RateLimitError do
      subscription.cancel
    end
  end

  test "sync_customer_email_to_stripe updates Stripe customer with owner email" do
    account = accounts(:"37s")
    owner = account.users.find_by(role: :owner) || account.users.first.tap { |u| u.update!(role: :owner) }
    subscription = account.create_subscription!(
      stripe_customer_id: "cus_test",
      plan_key: "monthly_v1",
      status: "active"
    )

    Stripe::Customer.expects(:update).with("cus_test", email: owner.identity.email_address).once

    subscription.sync_customer_email_to_stripe
  end

  test "sync_customer_email_to_stripe does nothing without stripe_customer_id" do
    account = accounts(:"37s")
    subscription = account.build_subscription(
      stripe_customer_id: nil,
      plan_key: "free_v1",
      status: "active"
    )

    Stripe::Customer.expects(:update).never

    subscription.sync_customer_email_to_stripe
  end

  test "sync_customer_email_to_stripe does nothing without owner" do
    account = accounts(:"37s")
    account.users.update_all(role: :member)
    subscription = account.create_subscription!(
      stripe_customer_id: "cus_test",
      plan_key: "monthly_v1",
      status: "active"
    )

    Stripe::Customer.expects(:update).never

    subscription.sync_customer_email_to_stripe
  end

  test "sync_customer_email_to_stripe does nothing when owner has no identity" do
    account = accounts(:"37s")
    owner = account.users.find_by(role: :owner) || account.users.first.tap { |u| u.update!(role: :owner) }
    owner.update_column(:identity_id, nil)
    subscription = account.create_subscription!(
      stripe_customer_id: "cus_test",
      plan_key: "monthly_v1",
      status: "active"
    )

    Stripe::Customer.expects(:update).never

    subscription.sync_customer_email_to_stripe
  end

  test "sync_customer_email_to_stripe treats deleted customer as success" do
    account = accounts(:"37s")
    account.users.find_by(role: :owner) || account.users.first.tap { |u| u.update!(role: :owner) }
    subscription = account.create_subscription!(
      stripe_customer_id: "cus_deleted",
      plan_key: "monthly_v1",
      status: "active"
    )

    Stripe::Customer.stubs(:update).raises(
      Stripe::InvalidRequestError.new("No such customer", {})
    )

    assert_nothing_raised do
      subscription.sync_customer_email_to_stripe
    end
  end
end
