/**
 * Tests for ContractManager component.
 *
 * Coverage:
 * 1. Loading state rendering.
 * 2. Contract list rendering.
 * 3. Empty state rendering.
 * 4. Activate button calls PATCH with {active: true}.
 * 5. "New Contract" button opens ContractForm.
 */

import { describe, it, expect, vi, beforeEach } from 'vitest'
import { screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { renderWithProviders } from '../test-utils'

// ---------------------------------------------------------------------------
// Mock apiClient
// ---------------------------------------------------------------------------

const mockGet = vi.fn()
const mockPost = vi.fn()
const mockPatch = vi.fn()

vi.mock('../api/client', () => ({
  default: {
    GET: (...args: unknown[]) => mockGet(...args),
    POST: (...args: unknown[]) => mockPost(...args),
    PATCH: (...args: unknown[]) => mockPatch(...args),
    DELETE: vi.fn(),
  },
  ApiError: class ApiError extends Error {
    status: number
    body: unknown
    constructor(status: number, body: unknown) {
      super(`API error ${status}`)
      this.name = 'ApiError'
      this.status = status
      this.body = body
    }
  },
  registerLoginRedirect: vi.fn(),
}))

// ---------------------------------------------------------------------------
// Fixtures
// ---------------------------------------------------------------------------

const ACTIVE_CONTRACT = {
  id: 1,
  name: 'My Active Contract',
  kind: 'manual',
  active: true,
  currency: 'EUR',
  created_at: '2026-06-01T00:00:00Z',
  updated_at: '2026-06-01T00:00:00Z',
}

const INACTIVE_CONTRACT = {
  id: 2,
  name: 'Inactive Contract',
  kind: 'tibber',
  active: false,
  currency: 'EUR',
  created_at: '2026-06-02T00:00:00Z',
  updated_at: '2026-06-02T00:00:00Z',
}

const PROFILES_RESPONSE = {
  profiles: [
    {
      kind: 'manual',
      label: 'Fixed / Variable Rate (NL, dual-tariff)',
      energy: {
        dual_tariff: true,
        buy: { normal: { unit: 'EUR/kWh' }, dal: { unit: 'EUR/kWh' } },
        sell: { normal: { unit: 'EUR/kWh' }, dal: { unit: 'EUR/kWh' } },
        energy_tax: { unit: 'EUR/kWh' },
        ode: { unit: 'EUR/kWh', default: 0 },
      },
      standing: {
        network_fee: { unit: 'EUR/month' },
        management_fee: { unit: 'EUR/month' },
      },
      credits: {
        heffingskorting: { unit: 'EUR/year' },
      },
    },
  ],
}

// ---------------------------------------------------------------------------
// Import component
// ---------------------------------------------------------------------------

import { ContractManager } from './ContractManager'

// ---------------------------------------------------------------------------
// Tests
// ---------------------------------------------------------------------------

describe('ContractManager', () => {
  beforeEach(() => vi.clearAllMocks())

  it('renders loading state initially', () => {
    // Never resolve so we stay in loading state
    mockGet.mockImplementation(() => new Promise(() => {}))

    renderWithProviders(<ContractManager />)

    expect(screen.getByTestId('contracts-loading')).toBeInTheDocument()
  })

  it('renders contract list when data loads', async () => {
    mockGet.mockImplementation((path: string) => {
      if (path === '/api/energy/contracts') {
        return Promise.resolve({
          data: { items: [ACTIVE_CONTRACT, INACTIVE_CONTRACT], total: 2 },
        })
      }
      return Promise.resolve({ data: null })
    })

    renderWithProviders(<ContractManager />)

    await waitFor(() => {
      expect(screen.getByTestId('contracts-table')).toBeInTheDocument()
    })

    expect(screen.getByText('My Active Contract')).toBeInTheDocument()
    expect(screen.getByText('Inactive Contract')).toBeInTheDocument()
    expect(screen.getByTestId('contract-active-badge-1')).toHaveTextContent('active')
    expect(screen.getByTestId('contract-active-badge-2')).toHaveTextContent('inactive')
  })

  it('renders empty state when no contracts exist', async () => {
    mockGet.mockResolvedValue({ data: { items: [], total: 0 } })

    renderWithProviders(<ContractManager />)

    await waitFor(() => {
      expect(screen.getByTestId('contracts-empty')).toBeInTheDocument()
    })
  })

  it('calls PATCH with active=true when Activate button clicked', async () => {
    const user = userEvent.setup()

    mockGet.mockImplementation((path: string) => {
      if (path === '/api/energy/contracts') {
        return Promise.resolve({
          data: { items: [INACTIVE_CONTRACT], total: 1 },
        })
      }
      return Promise.resolve({ data: null })
    })
    mockPatch.mockResolvedValue({
      data: { ...INACTIVE_CONTRACT, active: true, versions: [] },
    })

    renderWithProviders(<ContractManager />)

    await waitFor(() => {
      expect(screen.getByTestId(`contract-activate-${INACTIVE_CONTRACT.id}`)).toBeInTheDocument()
    })

    await user.click(screen.getByTestId(`contract-activate-${INACTIVE_CONTRACT.id}`))

    await waitFor(() => {
      expect(mockPatch).toHaveBeenCalledWith(
        '/api/energy/contracts/{contract_id}',
        expect.objectContaining({
          params: { path: { contract_id: INACTIVE_CONTRACT.id } },
          body: { active: true },
        }),
      )
    })
  })

  it('opens ContractForm when "New Contract" button is clicked', async () => {
    const user = userEvent.setup()

    mockGet.mockImplementation((path: string) => {
      if (path === '/api/energy/contracts') {
        return Promise.resolve({ data: { items: [], total: 0 } })
      }
      if (path === '/api/energy/profiles') {
        return Promise.resolve({ data: PROFILES_RESPONSE })
      }
      return Promise.resolve({ data: null })
    })

    renderWithProviders(<ContractManager />)

    await waitFor(() => {
      expect(screen.getByTestId('contract-new-button')).toBeInTheDocument()
    })

    await user.click(screen.getByTestId('contract-new-button'))

    await waitFor(() => {
      expect(screen.getByTestId('contract-form-modal')).toBeInTheDocument()
    })
  })
})
