import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
import type L from 'leaflet'
import { renderWithProviders, screen } from '../../../../tests/helpers/render'

// AZ-498 — self-hosted satellite tiles + drop classic/satellite toggle.
//
// Colocated under src/features/flights/__tests__/ per module-layout's "Tests"
// guidance: keeps the cross-component import surface clean (these tests
// reach into 05_flights internals — `./FlightMap`, `./MiniMap`, `./types` —
// which is intra-component access). Tests/ is reserved for cross-cutting
// black-box suites whose imports must go through public-API barrels.
//
// Covers the spec's fast-profile ACs:
//   AC-1 — env-resolved getTileUrl() returns the env var verbatim.
//   AC-2 — when the env var is unset, getTileUrl() returns the dev default
//          `http://localhost:5100/tiles/{z}/{x}/{y}` (cycle-2 assumption).
//   AC-3 — every <TileLayer> the SPA renders sets crossOrigin="use-credentials"
//          so the browser attaches the satellite-provider auth cookie.
//   AC-4 — the classic/satellite toggle, the `mapType` state, and the
//          `MiniMap.Props.mapType` prop are all gone.
//
// Notes:
//   - AC-5 is statically enforced by tsc on the new ImportMetaEnv shape +
//     the `.env.example` audit; no runtime test needed.
//   - AC-6, AC-7 are e2e/contract; AC-8 in the original spec misattributed
//     `tile_split_zoom*` (image-annotation surface) — see implementation
//     report. AC-9 is enforced by STC-ARCH-01 / STC-ARCH-02.

interface TileLayerProps {
  url?: string
  crossOrigin?: string
  attribution?: string
}

interface MapContainerProps {
  children?: React.ReactNode
  className?: string
}

vi.mock('react-leaflet', () => ({
  MapContainer: ({ children, className }: MapContainerProps) => (
    <div data-testid="map-container" className={className}>{children}</div>
  ),
  TileLayer: (props: TileLayerProps) => (
    <img
      data-testid="tile-layer"
      data-tile-url={props.url ?? ''}
      data-cross-origin={props.crossOrigin ?? ''}
      data-attribution={props.attribution ?? ''}
      alt=""
    />
  ),
  Marker: () => null,
  Popup: () => null,
  Polyline: () => null,
  Rectangle: () => null,
  CircleMarker: () => null,
  useMap: () => ({
    on: () => undefined,
    off: () => undefined,
    setView: () => undefined,
    removeLayer: () => undefined,
    getCenter: () => ({ lat: 0, lng: 0 }),
    invalidateSize: () => undefined,
  }),
  useMapEvents: () => null,
}))

// Leaflet itself is touched at import time by FlightMap (`L.polyline`,
// `L.Symbol.arrowHead`). Mock the bits the component reaches for so the
// import doesn't blow up under jsdom.
vi.mock('leaflet', () => {
  const Lstub = {
    polyline: () => ({ addTo: () => Lstub.polyline(), on: () => undefined }),
    polylineDecorator: () => ({ addTo: () => undefined }),
    Symbol: { arrowHead: () => ({}) },
    Icon: { Default: class { mergeOptions() {} } },
    Marker: class {},
    Layer: class {},
    LatLngBounds: class {},
  }
  return { default: Lstub }
})
vi.mock('leaflet/dist/leaflet.css', () => ({}))
vi.mock('leaflet-polylinedecorator', () => ({}))
vi.mock('../DrawControl', () => ({ default: () => null }))
vi.mock('../MapPoint', () => ({ default: () => null }))
vi.mock('../mapIcons', () => ({ currentPositionIcon: {} }))

import FlightMap from '../FlightMap'
import MiniMap from '../MiniMap'
import { getTileUrl, DEFAULT_SATELLITE_TILE_URL } from '../types'

const stubLatLng = { lat: 0, lng: 0 } as unknown as L.LatLng
const fixedPosition = { lat: 50, lng: 30 }

const baseFlightMapProps = {
  points: [],
  calculatedPointInfo: [],
  currentPosition: fixedPosition,
  rectangles: [],
  setRectangles: () => undefined,
  rectangleColor: 'red',
  actionMode: 'points' as const,
  onAddPoint: () => undefined,
  onUpdatePoint: () => undefined,
  onRemovePoint: () => undefined,
  onAltitudeChange: () => undefined,
  onMetaChange: () => undefined,
  onPolylineClick: () => undefined,
  onPositionChange: () => undefined,
  onMapMove: () => undefined,
}

describe('AZ-498 — getTileUrl() env resolution', () => {
  afterEach(() => {
    vi.unstubAllEnvs()
  })

  it('AC-1: returns the env-set VITE_SATELLITE_TILE_URL verbatim', () => {
    // Arrange
    vi.stubEnv('VITE_SATELLITE_TILE_URL', 'http://satellite-provider:5100/tiles/{z}/{x}/{y}')

    // Assert
    expect(getTileUrl()).toBe('http://satellite-provider:5100/tiles/{z}/{x}/{y}')
  })

  it('AC-2: returns the dev default when VITE_SATELLITE_TILE_URL is unset', () => {
    // Arrange
    vi.stubEnv('VITE_SATELLITE_TILE_URL', '')

    // Assert
    expect(getTileUrl()).toBe(DEFAULT_SATELLITE_TILE_URL)
    expect(DEFAULT_SATELLITE_TILE_URL).toBe('http://localhost:5100/tiles/{z}/{x}/{y}')
  })

  it('AC-2: strips trailing slashes off the env-set URL', () => {
    // Arrange
    vi.stubEnv('VITE_SATELLITE_TILE_URL', 'http://satellite-provider:5100/tiles/{z}/{x}/{y}/')

    // Assert
    expect(getTileUrl()).toBe('http://satellite-provider:5100/tiles/{z}/{x}/{y}')
  })
})

describe('AZ-498 — FlightMap satellite-only TileLayer', () => {
  beforeEach(() => {
    vi.stubEnv('VITE_SATELLITE_TILE_URL', '')
  })

  afterEach(() => {
    vi.unstubAllEnvs()
  })

  it('AC-3: <TileLayer> declares crossOrigin="use-credentials"', () => {
    // Act
    renderWithProviders(<FlightMap {...baseFlightMapProps} />, { withoutAuth: true })

    // Assert
    const tile = screen.getByTestId('tile-layer')
    expect(tile.getAttribute('data-cross-origin')).toBe('use-credentials')
  })

  it('AC-3: <TileLayer> renders the dev-default URL when env is unset', () => {
    // Act
    renderWithProviders(<FlightMap {...baseFlightMapProps} />, { withoutAuth: true })

    // Assert
    const tile = screen.getByTestId('tile-layer')
    expect(tile.getAttribute('data-tile-url')).toBe(DEFAULT_SATELLITE_TILE_URL)
  })

  it('AC-4: the classic/satellite toggle button is gone', () => {
    // Act
    renderWithProviders(<FlightMap {...baseFlightMapProps} />, { withoutAuth: true })

    // Assert
    expect(screen.queryByRole('button', { name: /satellite|classic/i })).toBeNull()
    // Only one <TileLayer> is mounted (no per-mode branching).
    expect(screen.getAllByTestId('tile-layer')).toHaveLength(1)
  })
})

describe('AZ-498 — MiniMap satellite-only TileLayer', () => {
  beforeEach(() => {
    vi.stubEnv('VITE_SATELLITE_TILE_URL', '')
  })

  afterEach(() => {
    vi.unstubAllEnvs()
  })

  it('AC-3: MiniMap <TileLayer> declares crossOrigin="use-credentials"', () => {
    // Act
    renderWithProviders(
      <MiniMap pointPosition={{ x: 0, y: 0, latlng: stubLatLng }} />,
      { withoutAuth: true },
    )

    // Assert
    const tile = screen.getByTestId('tile-layer')
    expect(tile.getAttribute('data-cross-origin')).toBe('use-credentials')
  })

  it('AC-4: MiniMap mounts with only `pointPosition` prop (no `mapType`)', () => {
    // Act — explicitly omit mapType; if MiniMap still required it, TS would
    // error at compile time. The runtime render also confirms the component
    // mounts with just the position prop.
    renderWithProviders(
      <MiniMap pointPosition={{ x: 0, y: 0, latlng: stubLatLng }} />,
      { withoutAuth: true },
    )

    // Assert
    expect(screen.getByTestId('tile-layer')).toBeInTheDocument()
  })
})
