import {
  Accordion,
  Badge,
  Box,
  Divider,
  Drawer,
  Group,
  Tabs,
  TabsList,
  Text,
  Tooltip,
  UnstyledButton
} from '@mantine/core';
import { Airport, AirportCategory } from '@lib/airport.types.ts';
import { getMarkerColor, Metar } from '@lib/metar.types.ts';
import { CSSProperties, forwardRef, ReactNode, useEffect, useState } from 'react';
import { getMetars } from '@lib/metar.ts';
import { useMediaQuery } from '@mantine/hooks';
import { IconViewfinder } from '@tabler/icons-react';
import { RunwayTable } from '@components/AirportDrawer/RunwayTable.tsx';
import { CommunicationTable } from '@components/AirportDrawer/CommunicationTable.tsx';
import { useMap } from 'react-leaflet';
import type { Map as LeafletMap } from 'leaflet';

export function AirportDrawer({
  airport,
  setAirport
}: {
  airport: Airport | null;
  setAirport: (airport: Airport | null) => void;
}) {
  const [metar, setMetar] = useState<Metar | undefined>(undefined);
  const isMobile = useMediaQuery('(max-width: 768px)');
  const map = useMap();

  useEffect(() => {
    if (!airport) return;
    function updateMetar() {
      if (!airport) return;
      getMetars({ icaos: [airport.icao] }).then((m) => {
        if (m.length > 0) {
          setMetar(m[0]);
        } else {
          setMetar(undefined);
        }
      });
    }

    updateMetar();

    const interval = setInterval(updateMetar, 60000);

    return () => clearInterval(interval);
  }, [airport]);

  if (!airport) {
    return null;
  }

  const metarColor = getMarkerColor(metar?.flight_category || 'UNKN');

  return (
    <Drawer.Root
      opened={true}
      onClose={() => setAirport(null)}
      withinPortal
      zIndex={1000}
      styles={{ root: { padding: 0, margin: 0, width: 0, height: 0, backgroundColor: 'red' } }}
      padding='md'
      size={isMobile ? '100%' : 'md'}
      position='left'
      closeOnClickOutside={false}
    >
      <Drawer.Content>
        <Drawer.Header>
          <Drawer.Title>
            <Text size={'xl'}>{airport.name}</Text>
          </Drawer.Title>
          <Drawer.CloseButton />
        </Drawer.Header>
        <Drawer.Body>
          <Box mb='lg'>
            {metar && metar.flight_category && (
              <Group
                justify='space-between'
                mb='md'
                style={{
                  backgroundColor: '#32495f',
                  borderTop: '1px solid #1a242f',
                  borderBottom: '1px solid #1a242f',
                  padding: '10px'
                }}
              >
                <Badge size='lg' color={metarColor}>
                  {metar.flight_category}
                </Badge>
                {/*<Text style={{ color: metarColor }}>{metar.flight_category}</Text>*/}
                <Tooltip zIndex={1001} label={new Date(metar.observation_time).toLocaleString()}>
                  <TimeSince date={metar.observation_time} />
                </Tooltip>
              </Group>
            )}
            <Tabs variant={'outline'} defaultValue={'info'}>
              <TabsList grow>
                <Tabs.Tab value={'info'}>Info</Tabs.Tab>
                <Tabs.Tab value={'weather'}>Weather</Tabs.Tab>
              </TabsList>
              <Tabs.Panel value={'info'}>
                <AirportInfo map={map} airport={airport} />
              </Tabs.Panel>
              <Tabs.Panel value={'weather'}>
                <WeatherInfo metar={airport.latest_metar} />
              </Tabs.Panel>
            </Tabs>
          </Box>
        </Drawer.Body>
      </Drawer.Content>
    </Drawer.Root>
  );
}

function AirportInfoSlot({ title, style, children }: { title?: string; style?: CSSProperties; children?: ReactNode }) {
  return (
    <div style={{ ...style }}>
      {title && (
        <Text size='xs' color='dimmed'>
          {title}
        </Text>
      )}
      <Box fw={500} size='sm'>
        {children}
      </Box>
    </div>
  );
}

function AirportInfoRow({ style, children }: { style?: CSSProperties; children: ReactNode }) {
  return (
    <div
      style={{
        display: 'flex',
        justifyContent: 'space-between',
        alignContent: 'center',
        padding: 'var(--mantine-spacing-sm) var(--mantine-spacing-lg)',
        borderTop: '1px solid light-dark(var(--mantine-color-gray-2), var(--mantine-color-dark-5))',
        ...style
      }}
    >
      {children}
    </div>
  );
}

function AirportInfo({ map, airport }: { map: LeafletMap; airport: Airport }) {
  function goToLocation(map: LeafletMap, latitude: number, longitude: number) {
    if (!map) return;
    map.setView([latitude, longitude], map.getZoom());
  }

  return (
    <div>
      <AirportInfoRow>
        <AirportInfoSlot title={'ICAO'} children={airport.icao} />
        <AirportInfoSlot title={'IATA'} children={airport.iata} />
        <AirportInfoSlot title={'LOCAL'} children={airport.local} />
        <AirportInfoSlot title={'Category'} children={airportCategoryToText(airport.category)} />
      </AirportInfoRow>
      <AirportInfoRow style={{ justifyContent: 'flex-start' }}>
        <AirportInfoSlot title={'Location'}>
          {airport.latitude}°, {airport.longitude}°
        </AirportInfoSlot>
        <AirportInfoSlot title={'Elevation'} style={{ paddingLeft: '1rem' }} children={`${airport.elevation_ft} ft`} />
        <AirportInfoSlot style={{ marginLeft: 'auto', paddingLeft: '1rem', paddingTop: '0.5rem' }}>
          <UnstyledButton
            onClick={() => {
              goToLocation(map, airport.latitude, airport.longitude);
            }}
          >
            <IconViewfinder />
          </UnstyledButton>
        </AirportInfoSlot>
      </AirportInfoRow>
      <Accordion chevronPosition={'right'} variant={'contained'}>
        {airport.runways != null && airport.runways.length > 0 && (
          <Accordion.Item value={'runways'}>
            <Accordion.Control>Runways</Accordion.Control>
            <Accordion.Panel>
              <RunwayTable runways={airport.runways} />
            </Accordion.Panel>
          </Accordion.Item>
        )}
        {airport.communications != null && airport.communications.length > 0 && (
          <Accordion.Item value={'communication'}>
            <Accordion.Control>Communication</Accordion.Control>
            <Accordion.Panel>
              <CommunicationTable communications={airport.communications} />
            </Accordion.Panel>
          </Accordion.Item>
        )}
      </Accordion>
      <Divider />
    </div>
  );
}

function WeatherInfo({ metar }: { metar?: Metar }) {
  if (metar) {
    return <>{metar.raw_text}</>;
  } else {
    return <>No METAR observation available</>;
  }
}

function airportCategoryToText(category: AirportCategory): string {
  switch (category) {
    case AirportCategory.SMALL:
      return 'Small';
    case AirportCategory.MEDIUM:
      return 'Medium';
    case AirportCategory.LARGE:
      return 'Large';
    case AirportCategory.HELIPORT:
      return 'Helipad';
    case AirportCategory.CLOSED:
      return 'Closed';
    case AirportCategory.SEAPLANE:
      return 'Seaplane Base';
    case AirportCategory.BALLOONPORT:
      return 'Balloon Port';
    default:
      return 'Unknown';
  }
}

const TimeSince = forwardRef<HTMLParagraphElement, { date: string }>(({ date }, ref) => {
  const inputDate = new Date(date);
  // @ts-expect-error doing arithmetic with dates
  const seconds = Math.floor((new Date() - inputDate) / 1000);

  if (seconds < 60) {
    const content = seconds + (seconds === 1 ? ' second ago' : ' seconds ago');
    return (
      <Text ref={ref} style={{ userSelect: 'none' }}>
        {content}
      </Text>
    );
  } else {
    const minutes = Math.floor(seconds / 60);
    const content = minutes + (minutes === 1 ? ' minute ago' : ' minutes ago');
    // If more than 60 minutes have passed, set the text color to yellow
    return (
      <Text ref={ref} style={{ color: minutes >= 60 ? '#fca903' : undefined, userSelect: 'none' }}>
        {content}
      </Text>
    );
  }
});
