/**
 * Tests for ContractForm component.
 *
 * Coverage:
 * 1. Renders profile fields dynamically from profile structure (not hardcoded)
 *    — verified by passing defaultKind so fields render automatically.
 * 2. Submit in create mode calls POST /api/energy/contracts.
 * 3. Submit in add-version mode calls POST /api/energy/contracts/{id}/versions.
 * 4. Cancel closes modal.
 */

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()

vi.mock('../api/client', () => ({
  default: {
    GET: (...args: unknown[]) => mockGet(...args),
    POST: (...args: unknown[]) => mockPost(...args),
    PATCH: vi.fn(),
    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 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' },
      },
    },
  ],
}

const CREATED_CONTRACT = {
  id: 1,
  name: 'Test Contract',
  kind: 'manual',
  active: false,
  currency: 'EUR',
  created_at: '2026-06-01T00:00:00Z',
  updated_at: '2026-06-01T00:00:00Z',
  versions: [],
}

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

import { ContractForm } from './ContractForm'

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

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

  it('renders profile fields dynamically from profile structure (not hardcoded)', async () => {
    mockGet.mockImplementation((path: string) => {
      if (path === '/api/energy/profiles') {
        return Promise.resolve({ data: PROFILES_RESPONSE })
      }
      return Promise.resolve({ data: null })
    })

    const onClose = vi.fn()
    const onSaved = vi.fn()

    // Pass defaultKind so the profile fields render automatically in create mode
    renderWithProviders(
      <ContractForm defaultKind="manual" onClose={onClose} onSaved={onSaved} />,
    )

    // Wait for profiles to load and fields to appear
    await waitFor(() => {
      expect(screen.getByTestId('contract-section-energy')).toBeInTheDocument()
    }, { timeout: 3000 })

    // Verify sections are rendered from profile structure (not hardcoded)
    expect(screen.getByTestId('contract-section-energy')).toBeInTheDocument()
    expect(screen.getByTestId('contract-section-standing')).toBeInTheDocument()
    expect(screen.getByTestId('contract-section-credits')).toBeInTheDocument()

    // Verify specific fields exist from the profile structure
    // "energy.buy.normal" → label "Buy Normal"
    expect(screen.getByTestId('contract-field-energy.buy.normal')).toBeInTheDocument()
    expect(screen.getByTestId('contract-field-energy.buy.dal')).toBeInTheDocument()
    expect(screen.getByTestId('contract-field-standing.network_fee')).toBeInTheDocument()
  })

  it('calls POST /api/energy/contracts in create mode', async () => {
    const user = userEvent.setup()

    mockGet.mockImplementation((path: string) => {
      if (path === '/api/energy/profiles') {
        return Promise.resolve({ data: PROFILES_RESPONSE })
      }
      return Promise.resolve({ data: null })
    })
    mockPost.mockResolvedValue({ data: CREATED_CONTRACT })

    const onClose = vi.fn()
    const onSaved = vi.fn()

    // Use defaultKind to ensure fields load without needing to interact with Select
    renderWithProviders(
      <ContractForm defaultKind="manual" onClose={onClose} onSaved={onSaved} />,
    )

    // Wait for form to render
    await waitFor(() => {
      expect(screen.getByTestId('contract-form')).toBeInTheDocument()
    })

    // Wait for profile fields to appear
    await waitFor(() => {
      expect(screen.getByTestId('contract-name')).toBeInTheDocument()
    })

    // Fill in contract name
    await user.type(screen.getByTestId('contract-name'), 'Test Contract')

    // Submit form
    await user.click(screen.getByTestId('contract-form-submit'))

    await waitFor(() => {
      expect(mockPost).toHaveBeenCalledWith(
        '/api/energy/contracts',
        expect.objectContaining({
          body: expect.objectContaining({
            name: 'Test Contract',
            kind: 'manual',
            currency: 'EUR',
          }),
        }),
      )
    }, { timeout: 3000 })
  })

  it('calls POST /api/energy/contracts/{id}/versions in add-version mode', async () => {
    const user = userEvent.setup()

    mockGet.mockImplementation((path: string) => {
      if (path === '/api/energy/profiles') {
        return Promise.resolve({ data: PROFILES_RESPONSE })
      }
      return Promise.resolve({ data: null })
    })
    mockPost.mockResolvedValue({ data: CREATED_CONTRACT })

    const onClose = vi.fn()
    const onSaved = vi.fn()

    renderWithProviders(
      <ContractForm contractId={1} defaultKind="manual" onClose={onClose} onSaved={onSaved} />,
    )

    // Wait for form to be ready (add-version mode)
    await waitFor(() => {
      expect(screen.getByTestId('contract-form')).toBeInTheDocument()
    })

    // In add-version mode, no name or kind fields shown
    expect(screen.queryByTestId('contract-name')).not.toBeInTheDocument()
    expect(screen.queryByTestId('contract-kind')).not.toBeInTheDocument()

    // Fill in effective_from (required in add-version mode)
    const effectiveDateInput = screen.getByTestId('contract-effective-from')
    await user.type(effectiveDateInput, '2026-07-01')

    // Submit form
    await user.click(screen.getByTestId('contract-form-submit'))

    await waitFor(() => {
      expect(mockPost).toHaveBeenCalledWith(
        '/api/energy/contracts/{contract_id}/versions',
        expect.objectContaining({
          params: { path: { contract_id: 1 } },
          body: expect.objectContaining({
            values: expect.any(Object),
          }),
        }),
      )
    }, { timeout: 3000 })
  })

  it('calls onClose when Cancel button is clicked', async () => {
    const user = userEvent.setup()

    mockGet.mockImplementation((path: string) => {
      if (path === '/api/energy/profiles') {
        return Promise.resolve({ data: PROFILES_RESPONSE })
      }
      return Promise.resolve({ data: null })
    })

    const onClose = vi.fn()
    const onSaved = vi.fn()

    renderWithProviders(
      <ContractForm onClose={onClose} onSaved={onSaved} />,
    )

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

    await user.click(screen.getByTestId('contract-form-cancel'))

    expect(onClose).toHaveBeenCalled()
  })

  it('prefills fields from the open version when in add-version mode', async () => {
    // FU11: add-version mode should auto-prefill rate fields from the contract's
    // current open version so the user only has to change what's different.
    const CONTRACT_DETAIL = {
      id: 42,
      name: 'My Contract',
      kind: 'manual',
      active: true,
      currency: 'EUR',
      created_at: '2026-01-01T00:00:00Z',
      updated_at: '2026-01-01T00:00:00Z',
      versions: [
        {
          id: 1,
          contract_id: 42,
          effective_from: '2026-01-01T00:00:00Z',
          effective_to: null,  // open version
          values: {
            energy: {
              buy: { normal: 0.133, dal: 0.127 },
              sell: { normal: 0.05, dal: 0.05 },
              energy_tax: 0.11,
              ode: 0.0,
            },
            standing: {
              network_fee: 30.0,
              management_fee: 60.0,
            },
            credits: {
              heffingskorting: 365.0,
            },
          },
          created_at: '2026-01-01T00:00:00Z',
        },
      ],
    }

    mockGet.mockImplementation((path: string) => {
      if (path === '/api/energy/profiles') {
        return Promise.resolve({ data: PROFILES_RESPONSE })
      }
      if (path === '/api/energy/contracts/{contract_id}') {
        return Promise.resolve({ data: CONTRACT_DETAIL })
      }
      return Promise.resolve({ data: null })
    })

    const onClose = vi.fn()
    const onSaved = vi.fn()

    renderWithProviders(
      <ContractForm contractId={42} defaultKind="manual" onClose={onClose} onSaved={onSaved} />,
    )

    const user = userEvent.setup()

    // Wait for the form to render and profile fields to appear
    await waitFor(() => {
      expect(screen.getByTestId('contract-section-energy')).toBeInTheDocument()
    }, { timeout: 3000 })

    // Wait for prefill to apply: both profile and contract detail queries must resolve.
    // Fill in the required effective_from date and submit; the submitted values
    // body.values should contain the prefilled rates from the open version.
    mockPost.mockResolvedValue({ data: {} })

    const effectiveInput = screen.getByTestId('contract-effective-from')
    await user.type(effectiveInput, '2026-07-01')

    await user.click(screen.getByTestId('contract-form-submit'))

    // The submitted body should contain the prefilled values from CONTRACT_DETAIL
    await waitFor(() => {
      expect(mockPost).toHaveBeenCalledWith(
        '/api/energy/contracts/{contract_id}/versions',
        expect.objectContaining({
          body: expect.objectContaining({
            values: expect.objectContaining({
              standing: expect.objectContaining({
                network_fee: 30,
                management_fee: 60,
              }),
            }),
          }),
        }),
      )
    }, { timeout: 3000 })
  })
})
