/**
 * RecordsPage — paginated lists + edit/delete for poo and location records (M2-T10).
 * Meter readings tab (read-only) per Modbus device dynamically appended (M5).
 *
 * - Poo list: GET /api/poo, query key ['poo', {limit, offset}], page size 100.
 * - Location list: GET /api/locations, query key ['locations', {limit, offset}], page size 100.
 * - Edit and delete use reusable components from src/records/.
 * - Delete has a二次确认 modal before calling DELETE.
 * - Pagination with Mantine Pagination; next/prev fetches per-page (no full-table pull).
 * - Meter tabs: one read-only tab per Modbus device; readings from /readings (last 24h, limit 1000).
 */

import { useState } from 'react'
import { useQuery } from '@tanstack/react-query'
import {
  Container,
  Title,
  Table,
  Pagination,
  Button,
  Group,
  Tabs,
  Text,
  Loader,
  Center,
  Alert,
  Stack,
  Badge,
  ScrollArea,
} from '@mantine/core'
import apiClient from '../api/client'
import { EditPooModal, EditLocationModal, ConfirmDeleteModal } from '../records'
import { useDeletePoo, useDeleteLocation } from '../records'
import type { PooRecord, LocationRecord } from '../records'
import { useDevices, useMetrics, useReadings } from '../energy/hooks'
import type { ModbusDevice, MetricInfo } from '../energy/hooks'
import { formatMetricValue } from '../energy/format'
import { formatLocalDateTime } from '../utils/datetime'

// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------

const PAGE_SIZE = 100

// ---------------------------------------------------------------------------
// Poo list section
// ---------------------------------------------------------------------------

function PooList() {
  const [page, setPage] = useState(1)
  const offset = (page - 1) * PAGE_SIZE

  const { data, isLoading, isError } = useQuery({
    queryKey: ['poo', { limit: PAGE_SIZE, offset }],
    queryFn: async () => {
      const res = await apiClient.GET('/api/poo', {
        params: { query: { limit: PAGE_SIZE, offset } },
      })
      return res.data
    },
  })

  const [editRecord, setEditRecord] = useState<PooRecord | null>(null)
  const [deleteRecord, setDeleteRecord] = useState<PooRecord | null>(null)

  const deleteMutation = useDeletePoo()

  async function handleDeleteConfirm() {
    if (!deleteRecord) return
    try {
      await deleteMutation.mutateAsync(deleteRecord.timestamp)
      setDeleteRecord(null)
    } catch {
      // Leave the modal open so the user can retry; error display is in the modal loading state.
    }
  }

  if (isLoading) {
    return (
      <Center pt="xl" data-testid="poo-loading">
        <Loader />
      </Center>
    )
  }

  if (isError || !data) {
    return (
      <Alert color="red" data-testid="poo-load-error">
        Failed to load poo records. Please refresh.
      </Alert>
    )
  }

  const totalPages = data.items.length === PAGE_SIZE ? page + 1 : page

  return (
    <Stack gap="md">
      <Group justify="space-between" align="center">
        <Text size="sm" c="dimmed" data-testid="poo-count">
          Page {page} · {data.items.length} record{data.items.length !== 1 ? 's' : ''} shown
        </Text>
        <Badge variant="outline" color="orange">
          offset {offset}
        </Badge>
      </Group>

      <ScrollArea>
        <Table striped highlightOnHover withTableBorder data-testid="poo-table">
          <Table.Thead>
            <Table.Tr>
              <Table.Th>Timestamp</Table.Th>
              <Table.Th>Status</Table.Th>
              <Table.Th>Latitude</Table.Th>
              <Table.Th>Longitude</Table.Th>
              <Table.Th style={{ textAlign: 'right' }}>Actions</Table.Th>
            </Table.Tr>
          </Table.Thead>
          <Table.Tbody>
            {data.items.length === 0 ? (
              <Table.Tr>
                <Table.Td colSpan={5}>
                  <Text c="dimmed" ta="center" size="sm">
                    No records.
                  </Text>
                </Table.Td>
              </Table.Tr>
            ) : (
              data.items.map((row) => (
                <Table.Tr key={row.timestamp} data-testid={`poo-row-${row.timestamp}`}>
                  <Table.Td style={{ whiteSpace: 'nowrap' }}>{row.timestamp}</Table.Td>
                  <Table.Td>{row.status}</Table.Td>
                  <Table.Td>{row.latitude}</Table.Td>
                  <Table.Td>{row.longitude}</Table.Td>
                  <Table.Td>
                    <Group justify="flex-end" gap="xs">
                      <Button
                        size="xs"
                        variant="outline"
                        onClick={() => setEditRecord(row)}
                        data-testid={`poo-edit-${row.timestamp}`}
                      >
                        Edit
                      </Button>
                      <Button
                        size="xs"
                        variant="outline"
                        color="red"
                        onClick={() => setDeleteRecord(row)}
                        data-testid={`poo-delete-${row.timestamp}`}
                      >
                        Delete
                      </Button>
                    </Group>
                  </Table.Td>
                </Table.Tr>
              ))
            )}
          </Table.Tbody>
        </Table>
      </ScrollArea>

      {totalPages > 1 && (
        <Pagination
          value={page}
          onChange={setPage}
          total={totalPages}
          data-testid="poo-pagination"
        />
      )}

      {/* Edit modal */}
      {editRecord && (
        <EditPooModal
          record={editRecord}
          onClose={() => setEditRecord(null)}
          onSaved={() => setEditRecord(null)}
        />
      )}

      {/* Delete confirmation modal */}
      {deleteRecord && (
        <ConfirmDeleteModal
          message={`Delete poo record at ${deleteRecord.timestamp}?`}
          loading={deleteMutation.isPending}
          onConfirm={handleDeleteConfirm}
          onCancel={() => setDeleteRecord(null)}
        />
      )}
    </Stack>
  )
}

// ---------------------------------------------------------------------------
// Location list section
// ---------------------------------------------------------------------------

function LocationList() {
  const [page, setPage] = useState(1)
  const offset = (page - 1) * PAGE_SIZE

  const { data, isLoading, isError } = useQuery({
    queryKey: ['locations', { limit: PAGE_SIZE, offset }],
    queryFn: async () => {
      const res = await apiClient.GET('/api/locations', {
        params: { query: { limit: PAGE_SIZE, offset } },
      })
      return res.data
    },
  })

  const [editRecord, setEditRecord] = useState<LocationRecord | null>(null)
  const [deleteRecord, setDeleteRecord] = useState<LocationRecord | null>(null)

  const deleteMutation = useDeleteLocation()

  async function handleDeleteConfirm() {
    if (!deleteRecord) return
    try {
      await deleteMutation.mutateAsync({
        person: deleteRecord.person,
        datetime: deleteRecord.datetime,
      })
      setDeleteRecord(null)
    } catch {
      // Leave modal open.
    }
  }

  if (isLoading) {
    return (
      <Center pt="xl" data-testid="location-loading">
        <Loader />
      </Center>
    )
  }

  if (isError || !data) {
    return (
      <Alert color="red" data-testid="location-load-error">
        Failed to load location records. Please refresh.
      </Alert>
    )
  }

  const totalPages = data.items.length === PAGE_SIZE ? page + 1 : page

  return (
    <Stack gap="md">
      <Group justify="space-between" align="center">
        <Text size="sm" c="dimmed" data-testid="location-count">
          Page {page} · {data.items.length} record{data.items.length !== 1 ? 's' : ''} shown
        </Text>
        <Badge variant="outline" color="blue">
          offset {offset}
        </Badge>
      </Group>

      <ScrollArea>
        <Table striped highlightOnHover withTableBorder data-testid="location-table">
          <Table.Thead>
            <Table.Tr>
              <Table.Th>Person</Table.Th>
              <Table.Th>Datetime</Table.Th>
              <Table.Th>Latitude</Table.Th>
              <Table.Th>Longitude</Table.Th>
              <Table.Th>Altitude</Table.Th>
              <Table.Th style={{ textAlign: 'right' }}>Actions</Table.Th>
            </Table.Tr>
          </Table.Thead>
          <Table.Tbody>
            {data.items.length === 0 ? (
              <Table.Tr>
                <Table.Td colSpan={6}>
                  <Text c="dimmed" ta="center" size="sm">
                    No records.
                  </Text>
                </Table.Td>
              </Table.Tr>
            ) : (
              data.items.map((row) => {
                const rowKey = `${row.person}__${row.datetime}`
                return (
                  <Table.Tr key={rowKey} data-testid={`location-row-${rowKey}`}>
                    <Table.Td>{row.person}</Table.Td>
                    <Table.Td style={{ whiteSpace: 'nowrap' }}>{row.datetime}</Table.Td>
                    <Table.Td>{row.latitude}</Table.Td>
                    <Table.Td>{row.longitude}</Table.Td>
                    <Table.Td>{row.altitude ?? '—'}</Table.Td>
                    <Table.Td>
                      <Group justify="flex-end" gap="xs">
                        <Button
                          size="xs"
                          variant="outline"
                          onClick={() => setEditRecord(row)}
                          data-testid={`location-edit-${rowKey}`}
                        >
                          Edit
                        </Button>
                        <Button
                          size="xs"
                          variant="outline"
                          color="red"
                          onClick={() => setDeleteRecord(row)}
                          data-testid={`location-delete-${rowKey}`}
                        >
                          Delete
                        </Button>
                      </Group>
                    </Table.Td>
                  </Table.Tr>
                )
              })
            )}
          </Table.Tbody>
        </Table>
      </ScrollArea>

      {totalPages > 1 && (
        <Pagination
          value={page}
          onChange={setPage}
          total={totalPages}
          data-testid="location-pagination"
        />
      )}

      {/* Edit modal */}
      {editRecord && (
        <EditLocationModal
          record={editRecord}
          onClose={() => setEditRecord(null)}
          onSaved={() => setEditRecord(null)}
        />
      )}

      {/* Delete confirmation modal */}
      {deleteRecord && (
        <ConfirmDeleteModal
          message={`Delete location record for ${deleteRecord.person} at ${deleteRecord.datetime}?`}
          loading={deleteMutation.isPending}
          onConfirm={handleDeleteConfirm}
          onCancel={() => setDeleteRecord(null)}
        />
      )}
    </Stack>
  )
}

// ---------------------------------------------------------------------------
// MeterReadingsTable — read-only table for a single Modbus device's readings
// ---------------------------------------------------------------------------

/** How many ms of history to show per meter tab (last 24 h). */
const METER_SPAN_MS = 24 * 60 * 60 * 1000
/** Upper bound on readings fetched; never a full-table pull. */
const METER_READINGS_LIMIT = 1000

interface MeterReadingsTableProps {
  device: ModbusDevice
}

/** Format an ISO timestamp for display (local timezone, 24-hour). */
function formatRecordedAt(iso: string): string {
  return formatLocalDateTime(iso)
}

function MeterReadingsTable({ device }: MeterReadingsTableProps) {
  const metricsQuery = useMetrics(device.uuid)
  const readingsQuery = useReadings(device.uuid, {
    spanMs: METER_SPAN_MS,
    limit: METER_READINGS_LIMIT,
  })

  const isLoading = metricsQuery.isLoading || readingsQuery.isLoading
  const isError = metricsQuery.isError || readingsQuery.isError

  const metrics: MetricInfo[] = metricsQuery.data?.metrics ?? []
  const readings = readingsQuery.data?.items ?? []
  const isTruncated = !isLoading && !isError && readings.length >= METER_READINGS_LIMIT

  if (isLoading) {
    return (
      <Center pt="xl" data-testid={`meter-loading-${device.uuid}`}>
        <Loader />
      </Center>
    )
  }

  if (isError) {
    return (
      <Alert color="red" data-testid={`meter-error-${device.uuid}`}>
        Failed to load meter readings. Please refresh.
      </Alert>
    )
  }

  const colSpan = 1 + metrics.length  // time column + one per metric

  return (
    <Stack gap="sm">
      {isTruncated && (
        <Text
          size="xs"
          c="dimmed"
          ta="right"
          data-testid={`meter-truncated-${device.uuid}`}
        >
          Showing the most recent {METER_READINGS_LIMIT} readings (within the last 24h)
        </Text>
      )}
      <ScrollArea>
        <Table striped highlightOnHover withTableBorder data-testid={`meter-table-${device.uuid}`}>
          <Table.Thead>
            <Table.Tr>
              <Table.Th style={{ whiteSpace: 'nowrap' }}>Recorded At</Table.Th>
              {metrics.map((m) => (
                <Table.Th key={m.key} style={{ whiteSpace: 'nowrap' }}>
                  {m.label}
                  {m.unit ? (
                    <Text component="span" size="xs" c="dimmed" ml={4}>
                      ({m.unit})
                    </Text>
                  ) : null}
                </Table.Th>
              ))}
            </Table.Tr>
          </Table.Thead>
          <Table.Tbody>
            {readings.length === 0 ? (
              <Table.Tr>
                <Table.Td colSpan={colSpan}>
                  <Text c="dimmed" ta="center" size="sm" data-testid={`meter-empty-${device.uuid}`}>
                    No readings in the last 24 hours.
                  </Text>
                </Table.Td>
              </Table.Tr>
            ) : (
              readings.map((row) => {
                const payload = row.payload as Record<string, unknown>
                return (
                  <Table.Tr
                    key={row.recorded_at}
                    data-testid={`meter-row-${device.uuid}`}
                  >
                    <Table.Td style={{ whiteSpace: 'nowrap' }}>
                      {formatRecordedAt(row.recorded_at)}
                    </Table.Td>
                    {metrics.map((m) => (
                      <Table.Td key={m.key} data-testid={`meter-cell-${device.uuid}-${m.key}`}>
                        {formatMetricValue(payload[m.key], m)}
                      </Table.Td>
                    ))}
                  </Table.Tr>
                )
              })
            )}
          </Table.Tbody>
        </Table>
      </ScrollArea>
    </Stack>
  )
}

// ---------------------------------------------------------------------------
// RecordsPage — top-level
// ---------------------------------------------------------------------------

export function RecordsPage() {
  const devicesQuery = useDevices()
  const devices: ModbusDevice[] = devicesQuery.data?.items ?? []

  return (
    <Container size="xl" pt="xl" pb="xl" data-testid="records-page">
      <Title order={2} mb="lg">
        Records
      </Title>

      <Tabs defaultValue="poo">
        <Tabs.List mb="md">
          <Tabs.Tab value="poo" data-testid="tab-poo">
            Poo
          </Tabs.Tab>
          <Tabs.Tab value="locations" data-testid="tab-locations">
            Locations
          </Tabs.Tab>
          {devices.map((d) => (
            <Tabs.Tab key={d.uuid} value={d.uuid} data-testid={`tab-meter-${d.uuid}`}>
              {d.friendly_name}
            </Tabs.Tab>
          ))}
        </Tabs.List>

        <Tabs.Panel value="poo">
          <PooList />
        </Tabs.Panel>

        <Tabs.Panel value="locations">
          <LocationList />
        </Tabs.Panel>

        {devices.map((d) => (
          <Tabs.Panel key={d.uuid} value={d.uuid}>
            <MeterReadingsTable device={d} />
          </Tabs.Panel>
        ))}
      </Tabs>
    </Container>
  )
}
