import { useMemo, useState } from 'react';
import {
  Alert,
  Button,
  Card,
  DatePicker,
  InputNumber,
  Select,
  Space,
  Table,
  Tag,
  Typography,
} from 'antd';
import type { ColumnsType } from 'antd/es/table';
import { DownloadOutlined, ReloadOutlined } from '@ant-design/icons';
import { keepPreviousData, useQuery } from '@tanstack/react-query';
import dayjs, { type Dayjs } from 'dayjs';
import {
  fetchRawMeasurements,
  listAllDevices,
  downloadRawMeasurementsExport,
  type RawMeasurementRow,
} from '../api/measurements';

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

// Hard cap on the in-page preview to keep the table fast. Excel export has its
// own cap (250 000 backend-side) since users actually want the whole dataset.
const PREVIEW_LIMIT_OPTIONS = [100, 200, 500, 1000];

export function MeasurementsPage() {
  const [range, setRange] = useState<[Dayjs, Dayjs]>(() => [
    dayjs().subtract(1, 'day').startOf('day'),
    dayjs().add(1, 'day').startOf('day'),
  ]);
  const [selectedDeviceIds, setSelectedDeviceIds] = useState<string[]>([]);
  const [limit, setLimit] = useState<number>(200);
  const [offset, setOffset] = useState<number>(0);
  const [exportRowCap, setExportRowCap] = useState<number>(100_000);

  const fromIso = range[0].toISOString();
  const toIso = range[1].toISOString();

  const { data: devices = [], isLoading: loadingDevices } = useQuery({
    queryKey: ['all-devices'],
    queryFn: listAllDevices,
  });

  const { data, isLoading, isFetching, error, refetch } = useQuery({
    queryKey: [
      'raw-measurements',
      fromIso,
      toIso,
      selectedDeviceIds.sort().join(','),
      limit,
      offset,
    ],
    queryFn: () =>
      fetchRawMeasurements({
        fromUtc: fromIso,
        toUtc: toIso,
        deviceIds: selectedDeviceIds.length > 0 ? selectedDeviceIds : undefined,
        limit,
        offset,
      }),
    placeholderData: keepPreviousData,
  });

  const deviceOptions = useMemo(
    () =>
      devices.map((d) => ({
        value: d.id,
        label: `${d.name} — ${d.siteName}`,
        disabled: !d.isActive,
      })),
    [devices],
  );

  const columns: ColumnsType<RawMeasurementRow> = [
    {
      title: 'Time (UTC)',
      dataIndex: 'time',
      key: 't',
      width: 180,
      render: (v: string) => new Date(v).toISOString().replace('T', ' ').slice(0, 19),
    },
    {
      title: 'Device',
      dataIndex: 'deviceName',
      key: 'd',
      render: (v: string) => <Text strong>{v}</Text>,
    },
    {
      title: 'Site',
      dataIndex: 'siteName',
      key: 's',
      render: (v: string | null) => v ?? <Text type="secondary">—</Text>,
    },
    {
      title: 'Active kW',
      dataIndex: 'activePowerKw',
      key: 'kw',
      align: 'right' as const,
      render: (v: number) => v.toFixed(3),
    },
    {
      title: 'kWh imported (cum.)',
      dataIndex: 'energyImportedKwh',
      key: 'imp',
      align: 'right' as const,
      render: (v: number | null) => (v == null ? '—' : v.toFixed(2)),
    },
    {
      title: 'kWh exported (cum.)',
      dataIndex: 'energyExportedKwh',
      key: 'exp',
      align: 'right' as const,
      render: (v: number | null) => (v == null ? '—' : v.toFixed(2)),
    },
    {
      title: 'PF',
      dataIndex: 'powerFactor',
      key: 'pf',
      align: 'right' as const,
      render: (v: number | null) => (v == null ? '—' : v.toFixed(3)),
    },
    {
      title: 'V',
      dataIndex: 'voltageV',
      key: 'v',
      align: 'right' as const,
      render: (v: number | null) => (v == null ? '—' : v.toFixed(1)),
    },
    {
      title: 'Hz',
      dataIndex: 'frequencyHz',
      key: 'hz',
      align: 'right' as const,
      render: (v: number | null) => (v == null ? '—' : v.toFixed(2)),
    },
  ];

  const totalCount = data?.totalCount ?? 0;
  const showingFrom = totalCount === 0 ? 0 : offset + 1;
  const showingTo = Math.min(offset + limit, totalCount);
  const canPrev = offset > 0;
  const canNext = offset + limit < totalCount;

  return (
    <Space direction="vertical" size="middle" style={{ width: '100%' }}>
      <Card size="small" title="Filters">
        <Space direction="vertical" size="small" style={{ width: '100%' }}>
          <Space wrap>
            <Text strong>Range (UTC):</Text>
            <RangePicker
              allowClear={false}
              value={range}
              showTime={false}
              onChange={(v) =>
                v &&
                v[0] &&
                v[1] &&
                (setRange([v[0].startOf('day'), v[1].endOf('day')]), setOffset(0))
              }
              ranges={{
                Today: [dayjs().startOf('day'), dayjs().add(1, 'day').startOf('day')],
                Yesterday: [dayjs().subtract(1, 'day').startOf('day'), dayjs().startOf('day')],
                'Last 7d': [
                  dayjs().subtract(7, 'day').startOf('day'),
                  dayjs().add(1, 'day').startOf('day'),
                ],
                'Last 30d': [
                  dayjs().subtract(30, 'day').startOf('day'),
                  dayjs().add(1, 'day').startOf('day'),
                ],
                'This month': [dayjs().startOf('month'), dayjs().add(1, 'day').startOf('day')],
                'All time': [dayjs('2020-01-01'), dayjs().add(1, 'day').startOf('day')],
              }}
            />
          </Space>

          <Space wrap style={{ width: '100%' }}>
            <Text strong style={{ minWidth: 80 }}>
              Meters:
            </Text>
            <Select
              mode="multiple"
              allowClear
              placeholder={loadingDevices ? 'Loading devices…' : 'All meters (leave empty)'}
              style={{ minWidth: 360, flex: 1 }}
              value={selectedDeviceIds}
              onChange={(v) => {
                setSelectedDeviceIds(v);
                setOffset(0);
              }}
              options={deviceOptions}
              maxTagCount="responsive"
              showSearch
              optionFilterProp="label"
            />
          </Space>

          <Space wrap>
            <Text strong>Preview rows:</Text>
            <Select
              value={limit}
              onChange={(v) => {
                setLimit(v);
                setOffset(0);
              }}
              options={PREVIEW_LIMIT_OPTIONS.map((n) => ({ value: n, label: n.toString() }))}
              style={{ width: 96 }}
            />
            <Text type="secondary">·</Text>
            <Text strong>Export row cap:</Text>
            <InputNumber
              value={exportRowCap}
              min={100}
              max={250_000}
              step={10_000}
              onChange={(v) => setExportRowCap(typeof v === 'number' ? v : 100_000)}
              style={{ width: 130 }}
            />
            <Text type="secondary" style={{ fontSize: 12 }}>
              max 250 000 — shrink the range if you exceed this
            </Text>
          </Space>
        </Space>
      </Card>

      {error && (
        <Alert
          type="error"
          showIcon
          message="Failed to load measurements"
          description={(error as Error).message}
        />
      )}

      <Card
        title={
          <Space>
            <Text strong>Measurements</Text>
            <Tag color="blue">{totalCount.toLocaleString()} rows match</Tag>
            {selectedDeviceIds.length > 0 && (
              <Tag>
                {selectedDeviceIds.length} meter{selectedDeviceIds.length === 1 ? '' : 's'} selected
              </Tag>
            )}
          </Space>
        }
        extra={
          <Space>
            <Button icon={<ReloadOutlined />} onClick={() => refetch()} loading={isFetching}>
              Refresh
            </Button>
            <Button
              type="primary"
              icon={<DownloadOutlined />}
              disabled={totalCount === 0}
              onClick={() =>
                downloadRawMeasurementsExport({
                  fromUtc: fromIso,
                  toUtc: toIso,
                  deviceIds: selectedDeviceIds.length > 0 ? selectedDeviceIds : undefined,
                  rowCap: exportRowCap,
                })
              }
            >
              Export to Excel
            </Button>
          </Space>
        }
      >
        <Table<RawMeasurementRow>
          rowKey={(r) => `${r.time}-${r.deviceName}`}
          size="small"
          columns={columns}
          dataSource={data?.rows ?? []}
          loading={isLoading}
          pagination={false}
          scroll={{ x: 'max-content' }}
        />

        <Space style={{ marginTop: 12, width: '100%', justifyContent: 'space-between' }}>
          <Text type="secondary">
            {totalCount === 0
              ? 'No measurements in this window.'
              : `Showing ${showingFrom.toLocaleString()}–${showingTo.toLocaleString()} of ${totalCount.toLocaleString()}`}
          </Text>
          <Space>
            <Button
              disabled={!canPrev || isFetching}
              onClick={() => setOffset(Math.max(0, offset - limit))}
            >
              Previous
            </Button>
            <Button disabled={!canNext || isFetching} onClick={() => setOffset(offset + limit)}>
              Next
            </Button>
          </Space>
        </Space>
      </Card>
    </Space>
  );
}
