/**
 * Tests for Billing API client functions
 */

import { describe, it, expect, vi, beforeEach } from 'vitest';
import apiClient from '../client';
import {
  getEntitlements,
  getCurrentSubscription,
  getPlans,
  getAddOns,
  getInvoices,
  getInvoice,
  Entitlements,
  Subscription,
  PlanVersion,
  AddOnProduct,
  Invoice,
} from '../billing';

// Mock the API client
vi.mock('../client', () => ({
  default: {
    get: vi.fn(),
  },
}));

describe('Billing API', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  describe('getEntitlements', () => {
    it('fetches entitlements from /api/me/entitlements/', async () => {
      const mockEntitlements: Entitlements = {
        can_use_sms_reminders: true,
        can_use_mobile_app: false,
        max_users: 10,
        max_resources: 25,
      };

      vi.mocked(apiClient.get).mockResolvedValueOnce({ data: mockEntitlements });

      const result = await getEntitlements();

      expect(apiClient.get).toHaveBeenCalledWith('/me/entitlements/');
      expect(result).toEqual(mockEntitlements);
    });

    it('returns empty object on error', async () => {
      vi.mocked(apiClient.get).mockRejectedValueOnce(new Error('Network error'));

      const result = await getEntitlements();

      expect(result).toEqual({});
    });
  });

  describe('getCurrentSubscription', () => {
    it('fetches subscription from /api/me/subscription/', async () => {
      const mockSubscription: Subscription = {
        id: 1,
        status: 'active',
        plan_version: {
          id: 10,
          name: 'Pro Plan v1',
          is_legacy: false,
          plan: { code: 'pro', name: 'Pro' },
          price_monthly_cents: 7900,
          price_yearly_cents: 79000,
        },
        current_period_start: '2024-01-01T00:00:00Z',
        current_period_end: '2024-02-01T00:00:00Z',
      };

      vi.mocked(apiClient.get).mockResolvedValueOnce({ data: mockSubscription });

      const result = await getCurrentSubscription();

      expect(apiClient.get).toHaveBeenCalledWith('/me/subscription/');
      expect(result).toEqual(mockSubscription);
    });

    it('returns null when no subscription (404)', async () => {
      const error = { response: { status: 404 } };
      vi.mocked(apiClient.get).mockRejectedValueOnce(error);

      const result = await getCurrentSubscription();

      expect(result).toBeNull();
    });
  });

  describe('getPlans', () => {
    it('fetches public plans from /api/billing/plans/', async () => {
      const mockPlans: PlanVersion[] = [
        {
          id: 1,
          name: 'Free Plan',
          is_legacy: false,
          is_public: true,
          plan: { code: 'free', name: 'Free' },
          price_monthly_cents: 0,
          price_yearly_cents: 0,
        },
        {
          id: 2,
          name: 'Pro Plan',
          is_legacy: false,
          is_public: true,
          plan: { code: 'pro', name: 'Pro' },
          price_monthly_cents: 7900,
          price_yearly_cents: 79000,
        },
      ];

      vi.mocked(apiClient.get).mockResolvedValueOnce({ data: mockPlans });

      const result = await getPlans();

      expect(apiClient.get).toHaveBeenCalledWith('/billing/plans/');
      expect(result).toEqual(mockPlans);
      expect(result).toHaveLength(2);
    });
  });

  describe('getAddOns', () => {
    it('fetches active add-ons from /api/billing/addons/', async () => {
      const mockAddOns: AddOnProduct[] = [
        {
          id: 1,
          code: 'sms_pack',
          name: 'SMS Pack',
          price_monthly_cents: 500,
          price_one_time_cents: 0,
          is_stackable: false,
          is_active: true,
        },
      ];

      vi.mocked(apiClient.get).mockResolvedValueOnce({ data: mockAddOns });

      const result = await getAddOns();

      expect(apiClient.get).toHaveBeenCalledWith('/billing/addons/');
      expect(result).toEqual(mockAddOns);
    });
  });

  describe('getInvoices', () => {
    it('fetches invoices from /api/billing/invoices/', async () => {
      const mockInvoices: Invoice[] = [
        {
          id: 1,
          status: 'paid',
          period_start: '2024-01-01T00:00:00Z',
          period_end: '2024-02-01T00:00:00Z',
          subtotal_amount: 7900,
          total_amount: 7900,
          plan_name_at_billing: 'Pro Plan',
          created_at: '2024-01-01T00:00:00Z',
        },
      ];

      vi.mocked(apiClient.get).mockResolvedValueOnce({ data: mockInvoices });

      const result = await getInvoices();

      expect(apiClient.get).toHaveBeenCalledWith('/billing/invoices/');
      expect(result).toEqual(mockInvoices);
    });
  });

  describe('getInvoice', () => {
    it('fetches a single invoice by ID', async () => {
      const mockInvoice: Invoice = {
        id: 1,
        status: 'paid',
        period_start: '2024-01-01T00:00:00Z',
        period_end: '2024-02-01T00:00:00Z',
        subtotal_amount: 7900,
        total_amount: 7900,
        plan_name_at_billing: 'Pro Plan',
        created_at: '2024-01-01T00:00:00Z',
        lines: [
          {
            id: 1,
            line_type: 'plan',
            description: 'Pro Plan',
            quantity: 1,
            unit_amount: 7900,
            total_amount: 7900,
          },
        ],
      };

      vi.mocked(apiClient.get).mockResolvedValueOnce({ data: mockInvoice });

      const result = await getInvoice(1);

      expect(apiClient.get).toHaveBeenCalledWith('/billing/invoices/1/');
      expect(result).toEqual(mockInvoice);
    });

    it('returns null when invoice not found (404)', async () => {
      const error = { response: { status: 404 } };
      vi.mocked(apiClient.get).mockRejectedValueOnce(error);

      const result = await getInvoice(999);

      expect(result).toBeNull();
    });
  });
});
