import {
  AimOutlined,
  BellOutlined,
  EnvironmentOutlined,
  DeleteOutlined,
  RadarChartOutlined,
} from '@ant-design/icons';
import { Alert, Button, Empty, Flex, Input, InputNumber, Space, Switch, Tag, Typography, message } from 'antd';
import { forwardRef, useMemo, useState } from 'react';
import { EmbeddedMapUI } from '../../components/embeddedMap';
import { useGpsLayer } from '../../layer';
import { WidgetShell } from '../core';
import type { WidgetHandle } from '../core';
import './GpsSampleWidget.css';

const { Paragraph, Text, Title } = Typography;

export type GpsSampleWidgetProps = {
  cardWrapper?: boolean;
};

function formatCoordinate(value: number | null | undefined) {
  return typeof value === 'number' ? value.toFixed(6) : '-';
}

function formatDistanceMeters(value: number) {
  return `${Math.round(value).toLocaleString()}m`;
}

function formatTimestamp(value: number | string | null | undefined) {
  if (!value) {
    return '-';
  }

  return new Intl.DateTimeFormat('ko-KR', {
    dateStyle: 'short',
    timeStyle: 'medium',
  }).format(new Date(value));
}

function toRadians(value: number) {
  return (value * Math.PI) / 180;
}

function calculateDistanceMeters(
  latitudeA: number,
  longitudeA: number,
  latitudeB: number,
  longitudeB: number,
) {
  const earthRadiusMeters = 6371000;
  const deltaLatitude = toRadians(latitudeB - latitudeA);
  const deltaLongitude = toRadians(longitudeB - longitudeA);
  const sinLatitude = Math.sin(deltaLatitude / 2);
  const sinLongitude = Math.sin(deltaLongitude / 2);
  const root =
    sinLatitude * sinLatitude +
    Math.cos(toRadians(latitudeA)) *
      Math.cos(toRadians(latitudeB)) *
      sinLongitude *
      sinLongitude;

  return 2 * earthRadiusMeters * Math.atan2(Math.sqrt(root), Math.sqrt(1 - root));
}

export const GpsSampleWidget = forwardRef<WidgetHandle, GpsSampleWidgetProps>(function GpsSampleWidget(
  { cardWrapper },
  ref,
) {
  const [messageApi, contextHolder] = message.useMessage();
  const [anchorName, setAnchorName] = useState('');
  const {
    enabled,
    supported,
    permissionState,
    currentPosition,
    anchors,
    config,
    selectedAnchorId,
    anchorPresence,
    events,
    errorMessage,
    enableGps,
    disableGps,
    saveCurrentAnchor,
    removeAnchor,
    selectAnchor,
    updateConfig,
    clearEvents,
  } = useGpsLayer();

  const selectedAnchor = anchors.find((anchor) => anchor.id === selectedAnchorId) ?? null;
  const focusTarget = selectedAnchor ?? (currentPosition ? { ...currentPosition, name: '현재 위치' } : null);
  const distanceToSelectedAnchor =
    selectedAnchor && currentPosition
      ? calculateDistanceMeters(
          currentPosition.latitude,
          currentPosition.longitude,
          selectedAnchor.latitude,
          selectedAnchor.longitude,
        )
      : null;

  const locationSummary = useMemo(
    () => [
      {
        label: '위도',
        value: formatCoordinate(currentPosition?.latitude),
      },
      {
        label: '경도',
        value: formatCoordinate(currentPosition?.longitude),
      },
      {
        label: '정확도',
        value: currentPosition?.accuracy ? `±${Math.round(currentPosition.accuracy)}m` : '-',
      },
      {
        label: '마지막 갱신',
        value: formatTimestamp(currentPosition?.timestamp),
      },
    ],
    [currentPosition],
  );

  return (
    <WidgetShell
      ref={ref}
      id="gps-sample-widget"
      title="GPS Sample Widget"
      cardWrapper={cardWrapper}
      features={['component-sample', 'feature-registry', 'imperative-handle', 'docs']}
      featureSlot={
        <Tag icon={<RadarChartOutlined />} color="cyan">
          Layer Context Hook
        </Tag>
      }
    >
      {contextHolder}
      <div className="gps-sample-widget">
        <div className="gps-sample-widget__hero">
          <section className="gps-sample-widget__hero-card">
            <Space align="start" size={12}>
              <Tag color={enabled ? 'blue' : 'default'} icon={<AimOutlined />}>
                GPS {enabled ? 'ON' : 'OFF'}
              </Tag>
              <Tag color={supported ? 'green' : 'red'}>
                {supported ? `권한 상태: ${permissionState}` : '브라우저 미지원'}
              </Tag>
              <Tag icon={<BellOutlined />} color="gold">
                반경 {config.radiusMeters}m
              </Tag>
            </Space>

            <div>
              <Title level={4}>실시간 GPS 좌표와 거점 지오펜스를 한 레이어에서 관리합니다.</Title>
              <Paragraph className="gps-sample-widget__hero-copy">
                현재 좌표를 즉시 거점으로 저장하고, In/Out 푸시 알림 설정과 반경을 조절한 뒤, 선택한
                거점을 하단 지도에서 바로 확인할 수 있습니다.
              </Paragraph>
            </div>

            <div className="gps-sample-widget__metrics">
              {locationSummary.map((item) => (
                <div key={item.label} className="gps-sample-widget__metric">
                  <Text type="secondary">{item.label}</Text>
                  <span className="gps-sample-widget__metric-value">{item.value}</span>
                </div>
              ))}
            </div>

            <div className="gps-sample-widget__actions">
              <Space size={12}>
                <Switch
                  checked={enabled}
                  disabled={!supported}
                  onChange={(checked) => {
                    if (checked) {
                      enableGps();
                      return;
                    }

                    disableGps();
                  }}
                  checkedChildren="GPS ON"
                  unCheckedChildren="GPS OFF"
                />
                <Text type="secondary">브라우저 Geolocation watchPosition 사용</Text>
              </Space>
            </div>

            {!supported ? (
              <Alert type="error" message="현재 브라우저는 GPS 기능을 지원하지 않습니다." showIcon />
            ) : null}
            {errorMessage ? <Alert type="warning" message={errorMessage} showIcon /> : null}
          </section>

          <section className="gps-sample-widget__panel">
            <Flex vertical gap={16}>
              <div>
                <Text strong>현재 좌표를 거점으로 등록</Text>
                <Paragraph type="secondary">
                  저장된 거점은 Local Storage에 유지되고, 선택 즉시 하단 지도 중심이 해당 위치로 이동합니다.
                </Paragraph>
              </div>
              <div className="gps-sample-widget__quick-form">
                <Input
                  placeholder="거점명 입력"
                  value={anchorName}
                  onChange={(event) => {
                    setAnchorName(event.target.value);
                  }}
                  onPressEnter={() => {
                    const result = saveCurrentAnchor(anchorName || `거점 ${anchors.length + 1}`);

                    if (!result.ok) {
                      void messageApi.warning(result.message);
                      return;
                    }

                    setAnchorName('');
                    void messageApi.success(`${result.anchor?.name ?? '거점'} 저장 완료`);
                  }}
                />
                <Button
                  type="primary"
                  icon={<EnvironmentOutlined />}
                  onClick={() => {
                    const result = saveCurrentAnchor(anchorName || `거점 ${anchors.length + 1}`);

                    if (!result.ok) {
                      void messageApi.warning(result.message);
                      return;
                    }

                    setAnchorName('');
                    void messageApi.success(`${result.anchor?.name ?? '거점'} 저장 완료`);
                  }}
                >
                  현재 위치 저장
                </Button>
              </div>

              <div className="gps-sample-widget__config">
                <div className="gps-sample-widget__config-row">
                  <Space>
                    <Switch
                      checked={config.notifyOnEnter}
                      onChange={(checked) => {
                        updateConfig({ notifyOnEnter: checked });
                      }}
                    />
                    <Text>거점 In 푸시알림</Text>
                  </Space>
                  <Space>
                    <Switch
                      checked={config.notifyOnExit}
                      onChange={(checked) => {
                        updateConfig({ notifyOnExit: checked });
                      }}
                    />
                    <Text>거점 Out 푸시알림</Text>
                  </Space>
                </div>
                <div className="gps-sample-widget__config-row">
                  <Text>반경 거리 설정</Text>
                  <InputNumber
                    min={30}
                    max={5000}
                    step={10}
                    addonAfter="m"
                    value={config.radiusMeters}
                    onChange={(value) => {
                      updateConfig({ radiusMeters: Number(value ?? config.radiusMeters) });
                    }}
                  />
                </div>
              </div>
            </Flex>
          </section>
        </div>

        <div className="gps-sample-widget__panel-grid">
          <section className="gps-sample-widget__panel">
            <div className="gps-sample-widget__event-head">
              <div>
                <Text strong>등록된 거점</Text>
                <Paragraph type="secondary">
                  거점명을 선택하면 하단 지도에서 위치를 확인할 수 있고, 현재 좌표와의 In / Out 상태도 같이 봅니다.
                </Paragraph>
              </div>
              <Tag color="blue">{anchors.length}개</Tag>
            </div>

            {anchors.length === 0 ? (
              <Empty description="저장된 거점이 없습니다." image={Empty.PRESENTED_IMAGE_SIMPLE} />
            ) : (
              <div className="gps-sample-widget__anchor-list">
                {anchors.map((anchor) => {
                  const active = anchor.id === selectedAnchorId;
                  const isInside = anchorPresence[anchor.id];
                  const distance =
                    currentPosition &&
                    calculateDistanceMeters(
                      currentPosition.latitude,
                      currentPosition.longitude,
                      anchor.latitude,
                      anchor.longitude,
                    );

                  return (
                    <article
                      key={anchor.id}
                      className={[
                        'gps-sample-widget__anchor-item',
                        active ? 'gps-sample-widget__anchor-item--active' : null,
                      ]
                        .filter(Boolean)
                        .join(' ')}
                    >
                      <div className="gps-sample-widget__anchor-head">
                        <div className="gps-sample-widget__anchor-meta">
                          <Text strong>{anchor.name}</Text>
                          <Text type="secondary">
                            {formatCoordinate(anchor.latitude)}, {formatCoordinate(anchor.longitude)}
                          </Text>
                        </div>
                        <Space wrap>
                          <Tag color={isInside ? 'green' : 'default'}>{isInside ? 'IN' : 'OUT'}</Tag>
                          {distance !== null && distance !== undefined ? (
                            <Tag>{formatDistanceMeters(distance)}</Tag>
                          ) : null}
                        </Space>
                      </div>

                      <div className="gps-sample-widget__anchor-actions">
                        <Button
                          type={active ? 'primary' : 'default'}
                          onClick={() => {
                            selectAnchor(anchor.id);
                          }}
                        >
                          지도에서 보기
                        </Button>
                        <Button
                          danger
                          icon={<DeleteOutlined />}
                          onClick={() => {
                            removeAnchor(anchor.id);
                          }}
                        >
                          삭제
                        </Button>
                      </div>
                    </article>
                  );
                })}
              </div>
            )}
          </section>

          <section className="gps-sample-widget__panel">
            <div className="gps-sample-widget__event-head">
              <div>
                <Text strong>최근 지오펜스 이벤트</Text>
                <Paragraph type="secondary">반경 경계 진입/이탈 이력이 최근 순서대로 쌓입니다.</Paragraph>
              </div>
              <Button onClick={clearEvents}>초기화</Button>
            </div>

            {events.length === 0 ? (
              <Empty description="아직 감지된 이벤트가 없습니다." image={Empty.PRESENTED_IMAGE_SIMPLE} />
            ) : (
              <div className="gps-sample-widget__event-list">
                {events.map((event) => (
                  <div key={event.id} className="gps-sample-widget__event-item">
                    <Space direction="vertical" size={2}>
                      <Space wrap>
                        <Tag color={event.type === 'enter' ? 'green' : 'orange'}>
                          {event.type === 'enter' ? 'IN' : 'OUT'}
                        </Tag>
                        <Text strong>{event.anchorName}</Text>
                        <Text type="secondary">{formatDistanceMeters(event.distanceMeters)}</Text>
                      </Space>
                      <Text type="secondary">{formatTimestamp(event.createdAt)}</Text>
                    </Space>
                  </div>
                ))}
              </div>
            )}
          </section>
        </div>

        <section className="gps-sample-widget__map-card">
          {focusTarget ? (
            <EmbeddedMapUI
              title={selectedAnchor ? `${selectedAnchor.name} 거점 지도` : '현재 GPS 위치'}
              description={
                selectedAnchor
                  ? `선택한 거점 중심으로 지도를 고정했습니다. 반경 ${config.radiusMeters}m 오버레이 정확도를 위해 지도 이동은 잠금 처리합니다.`
                  : '선택한 거점이 없어서 현재 GPS 위치를 지도 중심으로 사용합니다.'
              }
              latitude={focusTarget.latitude}
              longitude={focusTarget.longitude}
              zoom={16}
              height={360}
              markerLabel={selectedAnchor ? '선택 거점' : '현재 위치'}
              radiusMeters={selectedAnchor ? config.radiusMeters : undefined}
              lockViewport={Boolean(selectedAnchor)}
              secondaryMarker={
                selectedAnchor && currentPosition
                  ? {
                      latitude: currentPosition.latitude,
                      longitude: currentPosition.longitude,
                      label: '현재 위치',
                    }
                  : null
              }
            />
          ) : (
            <Empty description="GPS를 켜거나 거점을 선택하면 지도가 표시됩니다." />
          )}

          {selectedAnchor && distanceToSelectedAnchor !== null ? (
            <Paragraph type="secondary" style={{ marginTop: 14, marginBottom: 0 }}>
              현재 좌표와 선택 거점의 직선거리는 {formatDistanceMeters(distanceToSelectedAnchor)} 입니다.
            </Paragraph>
          ) : null}
        </section>
      </div>
    </WidgetShell>
  );
});
