import { TABLE_SORT_DIRECTIONS } from '@/config/settings';
import { Table } from 'antd';
import dayjs from 'dayjs';
import React, { useEffect, useRef, useState } from 'react';
import { ResourceBreakdownItem } from '../../apis/resource';
import useQueryStorageBreakdown from '../services/use-query-storage-breakdown';
import useStorageColumns from './use-storage-columns';

type Scope = 'self' | 'all';
type Metric = 'storage_gb_days' | 'storage_gb_hours';
type GroupKey = 'volume' | 'user';

// The frontend metric keys (storage_gb_days/hours) map to the server's
// breakdown metric keys (gb_days/gb_hours).
const ORDER_BY_KEY: Record<Metric, string> = {
  storage_gb_days: 'gb_days',
  storage_gb_hours: 'gb_hours'
};

const PER_PAGE = 50;
// sort_by encodes order as a string (`-` prefix = descending), so the fetch
// effect dedupes naturally on the primitive. Default: GB-Days descending.
const DEFAULT_SORT = '-gb_days';

interface Props {
  groupKey: GroupKey;
  dateRange: [dayjs.Dayjs, dayjs.Dayjs];
  scope: Scope;
  selectedUsers: number[];
  selectedVolumes: number[];
  // Bumped by the parent when a filter changes, so each mounted table snaps
  // back to page 1 independently.
  pageResetKey?: number;
  refreshKey?: number;
}

/**
 * One storage breakdown table, owning its own page/sort/data. Both tabs mount
 * an instance (volume / user) and keep it alive (Tabs `forceRender`), so each
 * keeps its own pagination + sort and switching tabs neither refetches nor
 * resets the other.
 */
const StorageBreakdownTable: React.FC<Props> = ({
  groupKey,
  dateRange,
  scope,
  selectedUsers,
  selectedVolumes,
  pageResetKey = 0,
  refreshKey = 0
}) => {
  const [queryParams, setQueryParams] = useState<{
    page: number;
    perPage: number;
    sort_by: string;
  }>({ page: 1, perPage: PER_PAGE, sort_by: DEFAULT_SORT });
  const pendingPageResetRef = useRef(false);

  const { detailData, loading, fetchData } = useQueryStorageBreakdown({
    key: `storageBreakdown-${groupKey}`
  });

  const columns = useStorageColumns(groupKey);

  // Sort only — paging goes through handlePageChange, so this stays
  // page-agnostic and the two compose (matches the Tokens tab tables).
  const handleTableChange = (_pagination: any, _filters: any, sorter: any) => {
    const s = Array.isArray(sorter) ? sorter[0] : sorter;
    const field = ORDER_BY_KEY[s?.field as Metric];
    // Cleared (3rd click) or an unknown column → default GB-Days descending.
    const sort_by =
      !field || !s?.order
        ? DEFAULT_SORT
        : s.order === 'ascend'
          ? field
          : `-${field}`;
    // Only a real sort change snaps back to page 1; an unchanged sort_by
    // (e.g. the onChange that fires alongside a page click) is a no-op, so it
    // doesn't fight handlePageChange.
    setQueryParams((prev) =>
      prev.sort_by === sort_by ? prev : { ...prev, sort_by, page: 1 }
    );
  };

  const handlePageChange = (page: number, pageSize: number) => {
    setQueryParams((prev) => ({ ...prev, page, perPage: pageSize }));
  };

  // Filters changed upstream → snap back to page 1. Defer the fetch until the
  // page-1 render so we don't fire a stale page-N request first.
  useEffect(() => {
    if (queryParams.page !== 1) {
      pendingPageResetRef.current = true;
      setQueryParams((prev) => ({ ...prev, page: 1 }));
    }
  }, [pageResetKey]);

  useEffect(() => {
    if (pendingPageResetRef.current && queryParams.page !== 1) return;
    pendingPageResetRef.current = false;

    const descending = queryParams.sort_by.startsWith('-');
    fetchData({
      start_date: dateRange[0].format('YYYY-MM-DD'),
      end_date: dateRange[1].format('YYYY-MM-DD'),
      scope,
      filters:
        selectedUsers.length || selectedVolumes.length
          ? {
              ...(selectedUsers.length ? { creator_ids: selectedUsers } : {}),
              ...(selectedVolumes.length ? { volume_ids: selectedVolumes } : {})
            }
          : undefined,
      group_by: [groupKey],
      page: queryParams.page,
      perPage: queryParams.perPage,
      order_by: descending ? queryParams.sort_by.slice(1) : queryParams.sort_by,
      descending
    });
  }, [
    dateRange,
    scope,
    selectedUsers,
    selectedVolumes,
    queryParams.page,
    queryParams.perPage,
    queryParams.sort_by,
    refreshKey,
    fetchData
  ]);

  const rows: ResourceBreakdownItem[] = detailData?.items ?? [];

  return (
    <Table
      rowKey={(row) =>
        `${row.volume_id ?? ''}|${row.user_id ?? ''}|${row.volume_name ?? ''}`
      }
      dataSource={rows}
      columns={columns as any}
      loading={{ spinning: loading, size: 'middle' }}
      sortDirections={TABLE_SORT_DIRECTIONS}
      showSorterTooltip={false}
      onChange={handleTableChange}
      pagination={{
        size: 'middle',
        current: queryParams.page,
        pageSize: detailData?.pagination?.perPage ?? queryParams.perPage,
        total: detailData?.pagination?.total ?? 0,
        showSizeChanger: true,
        hideOnSinglePage: queryParams.perPage === PER_PAGE,
        onChange: handlePageChange
      }}
    />
  );
};

export default StorageBreakdownTable;
