/**
 * NASA Data Download Page
 * Downloads position data for celestial bodies from NASA Horizons API
 */
import { useState, useEffect } from 'react';
import {
  Row,
  Col,
  Card,
  Checkbox,
  DatePicker,
  Button,
  message,
  Badge,
  Spin,
  Typography,
  Collapse,
  Space,
  Progress,
  Calendar,
  Alert
} from 'antd';
import {
  DownloadOutlined,
  CheckCircleOutlined,
  CloseCircleOutlined,
  LoadingOutlined
} from '@ant-design/icons';
import type { CheckboxChangeEvent } from 'antd/es/checkbox';
import type { Dayjs } from 'dayjs';
import dayjs from 'dayjs';
import isBetween from 'dayjs/plugin/isBetween';
import { request } from '../../utils/request';

// Extend dayjs with isBetween plugin
dayjs.extend(isBetween);

const { Title, Text } = Typography;
const { RangePicker } = DatePicker;

interface CelestialBody {
  id: string;
  name: string;
  name_zh: string;
  type: string;
  is_active: boolean;
  description: string;
}

interface GroupedBodies {
  [type: string]: CelestialBody[];
}

export function NASADownload() {
  const [loading, setLoading] = useState(false);
  const [bodies, setBodies] = useState<GroupedBodies>({});
  const [selectedBodies, setSelectedBodies] = useState<string[]>([]);
  const [dateRange, setDateRange] = useState<[Dayjs, Dayjs]>([
    dayjs().subtract(1, 'month').startOf('month'),
    dayjs().subtract(1, 'month').endOf('month')
  ]);
  const [availableDates, setAvailableDates] = useState<Set<string>>(new Set());
  const [loadingDates, setLoadingDates] = useState(false);
  const [downloading, setDownloading] = useState(false);
  const [downloadProgress, setDownloadProgress] = useState({ current: 0, total: 0 });

  // Type name mapping
  const typeNames: Record<string, string> = {
    star: '恒星',
    planet: '行星',
    dwarf_planet: '矮行星',
    satellite: '卫星',
    probe: '探测器',
  };

  useEffect(() => {
    loadBodies();
  }, []);

  useEffect(() => {
    if (selectedBodies.length > 0) {
      loadAvailableDates();
    } else {
      setAvailableDates(new Set());
    }
  }, [selectedBodies, dateRange]);

  const loadBodies = async () => {
    setLoading(true);
    try {
      const { data } = await request.get('/celestial/positions/download/bodies');
      setBodies(data.bodies || {});
    } catch (error) {
      message.error('加载天体列表失败');
    } finally {
      setLoading(false);
    }
  };

  const loadAvailableDates = async () => {
    if (selectedBodies.length === 0) return;

    setLoadingDates(true);
    try {
      const allDates = new Set<string>();

      // Load available dates for the first selected body
      const bodyId = selectedBodies[0];
      const startDate = dateRange[0].format('YYYY-MM-DD');
      const endDate = dateRange[1].format('YYYY-MM-DD');

      const { data } = await request.get('/celestial/positions/download/status', {
        params: {
          body_id: bodyId,
          start_date: startDate,
          end_date: endDate
        }
      });

      data.available_dates.forEach((date: string) => {
        allDates.add(date);
      });

      setAvailableDates(allDates);
    } catch (error) {
      message.error('加载数据状态失败');
    } finally {
      setLoadingDates(false);
    }
  };

  const handleBodySelect = (bodyId: string, checked: boolean) => {
    setSelectedBodies(prev =>
      checked ? [...prev, bodyId] : prev.filter(id => id !== bodyId)
    );
  };

  const handleTypeSelectAll = (type: string, checked: boolean) => {
    const typeBodyIds = bodies[type].map(b => b.id);
    setSelectedBodies(prev => {
      if (checked) {
        return [...new Set([...prev, ...typeBodyIds])];
      } else {
        return prev.filter(id => !typeBodyIds.includes(id));
      }
    });
  };

  const handleDateRangeChange = (dates: any) => {
    if (dates && dates[0] && dates[1]) {
      setDateRange([dates[0], dates[1]]);
    }
  };

  const handleDownload = async (selectedDate?: Dayjs) => {
    if (selectedBodies.length === 0) {
      message.warning('请先选择至少一个天体');
      return;
    }

    let datesToDownload: string[] = [];

    if (selectedDate) {
      // Download single date
      datesToDownload = [selectedDate.format('YYYY-MM-DD')];
    } else {
      // Download all dates in range
      const start = dateRange[0];
      const end = dateRange[1];
      let current = start;

      while (current.isBefore(end) || current.isSame(end, 'day')) {
        datesToDownload.push(current.format('YYYY-MM-DD'));
        current = current.add(1, 'day');
      }
    }

    setDownloading(true);
    setDownloadProgress({ current: 0, total: datesToDownload.length });

    try {
      const { data } = await request.post('/celestial/positions/download', {
        body_ids: selectedBodies,
        dates: datesToDownload
      });

      setDownloadProgress({ current: datesToDownload.length, total: datesToDownload.length });

      if (data.total_success > 0) {
        message.success(`成功下载 ${data.total_success} 条数据${data.total_failed > 0 ? `，${data.total_failed} 条失败` : ''}`);
        // Reload available dates to show newly downloaded data
        loadAvailableDates();
      } else {
        message.error('下载失败');
      }
    } catch (error) {
      message.error('下载请求失败');
    } finally {
      setDownloading(false);
      setDownloadProgress({ current: 0, total: 0 });
    }
  };

  // Custom calendar cell renderer
  const dateCellRender = (value: Dayjs) => {
    const dateStr = value.format('YYYY-MM-DD');
    const hasData = availableDates.has(dateStr);
    const inRange = value.isBetween(dateRange[0], dateRange[1], 'day', '[]');

    if (!inRange) return null;

    return (
      <div style={{ textAlign: 'center', padding: '4px 0' }}>
        {hasData ? (
          <Badge status="success" text="" />
        ) : (
          <Badge status="default" text="" />
        )}
      </div>
    );
  };

  const disabledDate = (current: Dayjs) => {
    // Cannot select dates in the future
    return current && current.isAfter(dayjs(), 'day');
  };

  const handleCalendarDateClick = (date: Dayjs) => {
    const dateStr = date.format('YYYY-MM-DD');
    const hasData = availableDates.has(dateStr);
    const inRange = date.isBetween(dateRange[0], dateRange[1], 'day', '[]');

    if (!inRange) {
      message.warning('请选择在日期范围内的日期');
      return;
    }

    if (hasData) {
      message.info('该日期已有数据');
      return;
    }

    if (selectedBodies.length === 0) {
      message.warning('请先选择天体');
      return;
    }

    handleDownload(date);
  };

  return (
    <div>
      <Alert
        title="数据下载说明"
        description="选择左侧天体，右侧日历将显示数据可用性。点击未下载的日期可下载该天的位置数据（00:00 UTC）。"
        type="info"
        showIcon
        style={{ marginBottom: 16 }}
      />

      <Row gutter={16}>
        {/* Left: Body Selection */}
        <Col span={8}>
          <Card
            title="选择天体"
            loading={loading}
            extra={
              <Text type="secondary">
                已选择: {selectedBodies.length}
              </Text>
            }
          >
            <Collapse
              defaultActiveKey={['planet', 'dwarf_planet']}
              items={Object.entries(bodies).map(([type, typeBodies]) => ({
                key: type,
                label: (
                  <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
                    <span>{typeNames[type] || type}</span>
                    <Checkbox
                      checked={typeBodies.every(b => selectedBodies.includes(b.id))}
                      indeterminate={
                        typeBodies.some(b => selectedBodies.includes(b.id)) &&
                        !typeBodies.every(b => selectedBodies.includes(b.id))
                      }
                      onChange={(e) => {
                        e.stopPropagation();
                        handleTypeSelectAll(type, e.target.checked);
                      }}
                    >
                      全选
                    </Checkbox>
                  </div>
                ),
                children: (
                  <Space direction="vertical" style={{ width: '100%' }}>
                    {typeBodies.map((body) => (
                      <Checkbox
                        key={body.id}
                        checked={selectedBodies.includes(body.id)}
                        onChange={(e) => handleBodySelect(body.id, e.target.checked)}
                      >
                        {body.name_zh || body.name}
                        {!body.is_active && <Badge status="default" text="(未激活)" style={{ marginLeft: 8 }} />}
                      </Checkbox>
                    ))}
                  </Space>
                ),
              }))}
            />
          </Card>
        </Col>

        {/* Right: Date Selection and Calendar */}
        <Col span={16}>
          <Card
            title="选择下载日期"
            extra={
              <Space>
                <RangePicker
                  value={dateRange}
                  onChange={handleDateRangeChange}
                  disabledDate={disabledDate}
                  format="YYYY-MM-DD"
                  allowClear={false}
                />
                <Button
                  type="primary"
                  icon={<DownloadOutlined />}
                  onClick={() => handleDownload()}
                  disabled={selectedBodies.length === 0}
                  loading={downloading}
                >
                  下载范围内所有日期
                </Button>
              </Space>
            }
          >
            <Spin spinning={loadingDates} indicator={<LoadingOutlined spin />}>
              <div style={{ marginBottom: 16 }}>
                <Space>
                  <Badge status="success" text="已有数据" />
                  <Badge status="default" text="无数据（点击下载）" />
                </Space>
              </div>

              {downloading && (
                <div style={{ marginBottom: 16 }}>
                  <Progress
                    percent={Math.round((downloadProgress.current / downloadProgress.total) * 100)}
                    status="active"
                  />
                  <Text type="secondary">
                    正在下载: {downloadProgress.current} / {downloadProgress.total}
                  </Text>
                </div>
              )}

              <Calendar
                fullscreen={false}
                value={dateRange[0]}
                onSelect={handleCalendarDateClick}
                cellRender={dateCellRender}
                disabledDate={disabledDate}
                validRange={[dateRange[0], dateRange[1]]}
              />
            </Spin>
          </Card>
        </Col>
      </Row>
    </div>
  );
}
