import { useState, useEffect, useCallback } from 'react';
import { useSearchParams } from 'react-router-dom';
import type {
  Transaction,
  Account,
  Category,
  PaginatedResponse,
  GetTransactionsParams,
} from '@family-budget/shared';
import { getTransactions } from '../api/transactions';
import { getAccounts } from '../api/accounts';
import { getCategories } from '../api/categories';
import {
  TransactionFilters,
  type FiltersState,
} from '../components/TransactionFilters';
import { TransactionTable } from '../components/TransactionTable';
import { Pagination } from '../components/Pagination';
import { EditTransactionModal } from '../components/EditTransactionModal';
import { ImportModal } from '../components/ImportModal';
import { toISODate } from '../utils/format';

const PARAM_KEYS = [
  'from',
  'to',
  'accountId',
  'direction',
  'categoryId',
  'search',
  'amountMin',
  'amountMax',
  'onlyUnconfirmed',
  'sortBy',
  'sortOrder',
  'periodMode',
] as const;

function getDefaultFilters(): FiltersState {
  const now = new Date();
  const from = new Date(now.getFullYear(), now.getMonth(), 1);
  return {
    periodMode: 'month',
    from: toISODate(from),
    to: toISODate(now),
    accountId: '',
    direction: '',
    categoryId: '',
    search: '',
    amountMin: '',
    amountMax: '',
    onlyUnconfirmed: false,
    sortBy: 'date',
    sortOrder: 'desc',
  };
}

function filtersFromParams(params: URLSearchParams): Partial<FiltersState> {
  const out: Partial<FiltersState> = {};
  for (const key of PARAM_KEYS) {
    const v = params.get(key);
    if (v !== null) {
      if (key === 'onlyUnconfirmed') {
        out[key] = v === '1' || v === 'true';
      } else {
        (out as Record<string, unknown>)[key] = v;
      }
    }
  }
  return out;
}

function paramsFromUrl(params: URLSearchParams): {
  page: number;
  pageSize: number;
} {
  const p = params.get('page');
  const ps = params.get('pageSize');
  return {
    page: p ? Math.max(1, parseInt(p, 10) || 1) : 1,
    pageSize: ps ? parseInt(ps, 10) || 50 : 50,
  };
}

function filtersToParams(
  f: FiltersState,
  pageNum: number,
  pageSizeNum: number,
): URLSearchParams {
  const p = new URLSearchParams();
  if (f.from) p.set('from', f.from);
  if (f.to) p.set('to', f.to);
  if (f.accountId) p.set('accountId', f.accountId);
  if (f.direction) p.set('direction', f.direction);
  if (f.categoryId) p.set('categoryId', f.categoryId);
  if (f.search) p.set('search', f.search);
  if (f.amountMin) p.set('amountMin', f.amountMin);
  if (f.amountMax) p.set('amountMax', f.amountMax);
  if (f.onlyUnconfirmed) p.set('onlyUnconfirmed', '1');
  if (f.sortBy) p.set('sortBy', f.sortBy);
  if (f.sortOrder) p.set('sortOrder', f.sortOrder);
  if (f.periodMode) p.set('periodMode', f.periodMode);
  if (pageNum > 1) p.set('page', String(pageNum));
  if (pageSizeNum !== 50) p.set('pageSize', String(pageSizeNum));
  return p;
}

export function HistoryPage() {
  const [searchParams, setSearchParams] = useSearchParams();
  const urlFilters = filtersFromParams(searchParams);
  const { page: urlPage, pageSize: urlPageSize } = paramsFromUrl(searchParams);
  const defaultFilters = getDefaultFilters();
  const [filters, setFilters] = useState<FiltersState>(() => ({
    ...defaultFilters,
    ...urlFilters,
    periodMode:
      (urlFilters.periodMode as FiltersState['periodMode']) ??
      defaultFilters.periodMode,
  }));
  const [page, setPage] = useState(urlPage);
  const [pageSize, setPageSize] = useState(urlPageSize);
  const [data, setData] = useState<PaginatedResponse<Transaction> | null>(
    null,
  );
  const [loading, setLoading] = useState(false);
  const [accounts, setAccounts] = useState<Account[]>([]);
  const [categories, setCategories] = useState<Category[]>([]);
  const [editingTx, setEditingTx] = useState<Transaction | null>(null);
  const [showImport, setShowImport] = useState(false);

  useEffect(() => {
    getAccounts().then(setAccounts).catch(() => {});
    getCategories().then(setCategories).catch(() => {});
  }, []);

  useEffect(() => {
    const urlFilters = filtersFromParams(searchParams);
    const { page: p, pageSize: ps } = paramsFromUrl(searchParams);
    if (Object.keys(urlFilters).length > 0) {
      setFilters((prev) => ({
        ...getDefaultFilters(),
        ...urlFilters,
        periodMode:
          (urlFilters.periodMode as FiltersState['periodMode']) ??
          prev.periodMode,
      }));
    }
    setPage(p);
    setPageSize(ps);
  }, [searchParams]);

  const fetchData = useCallback(async () => {
    setLoading(true);
    try {
      const params: GetTransactionsParams = {
        page,
        pageSize,
        sortBy: filters.sortBy,
        sortOrder: filters.sortOrder,
      };
      if (filters.from) params.from = filters.from;
      if (filters.to) params.to = filters.to;
      if (filters.accountId) params.accountId = Number(filters.accountId);
      if (filters.direction) params.direction = filters.direction;
      if (filters.categoryId) params.categoryId = Number(filters.categoryId);
      if (filters.search) params.search = filters.search;
      if (filters.amountMin)
        params.amountMin = Math.round(Number(filters.amountMin) * 100);
      if (filters.amountMax)
        params.amountMax = Math.round(Number(filters.amountMax) * 100);
      if (filters.onlyUnconfirmed) params.onlyUnconfirmed = true;

      const result = await getTransactions(params);
      setData(result);
    } catch {
      // 401 handled by interceptor
    } finally {
      setLoading(false);
    }
  }, [filters, page, pageSize]);

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

  const handleFiltersChange = (newFilters: FiltersState) => {
    setFilters(newFilters);
    setPage(1);
    setSearchParams(filtersToParams(newFilters, 1, pageSize), {
      replace: true,
    });
  };


  const handleEditSave = () => {
    setEditingTx(null);
    fetchData();
  };

  const handleImportDone = () => {
    setShowImport(false);
    fetchData();
    getAccounts().then(setAccounts).catch(() => {});
  };

  return (
    <div className="page">
      <div className="page-header">
        <h1>История операций</h1>
        <button
          className="btn btn-primary"
          onClick={() => setShowImport(true)}
        >
          Импорт выписки
        </button>
      </div>

      <TransactionFilters
        filters={filters}
        onChange={handleFiltersChange}
        accounts={accounts}
        categories={categories}
      />

      <TransactionTable
        transactions={data?.items ?? []}
        loading={loading}
        onEdit={setEditingTx}
      />

      {data && (
        <Pagination
          page={data.page}
          pageSize={data.pageSize}
          totalItems={data.totalItems}
          totalPages={data.totalPages}
          onPageChange={(p) => {
            setPage(p);
            setSearchParams(
              filtersToParams(filters, p, pageSize),
              { replace: true },
            );
          }}
          onPageSizeChange={(size) => {
            setPageSize(size);
            setPage(1);
            setSearchParams(
              filtersToParams(filters, 1, size),
              { replace: true },
            );
          }}
        />
      )}

      {editingTx && (
        <EditTransactionModal
          transaction={editingTx}
          categories={categories}
          onClose={() => setEditingTx(null)}
          onSave={handleEditSave}
        />
      )}

      {showImport && (
        <ImportModal
          onClose={() => setShowImport(false)}
          onDone={handleImportDone}
        />
      )}
    </div>
  );
}
