import { useQuery, UseQueryOptions } from '@tanstack/react-query';
import { gql } from 'graphql-request';
import type { Dayjs } from 'dayjs';
import { fetchGraphQL, createQueryKey } from '../client';
import type { Account, AccountBalance, AccountType } from '@/types/accounting';

// Runtime validation for AccountType
const VALID_ACCOUNT_TYPES: AccountType[] = [
  'asset', 'liability', 'equity', 'revenue', 'cogs',
  'expense', 'personnel', 'financial', 'extraordinary'
];

function isValidAccountType(type: string): type is AccountType {
  return VALID_ACCOUNT_TYPES.includes(type as AccountType);
}

function parseAccountType(type: string, fallback: AccountType = 'asset'): AccountType {
  const normalized = type.toLowerCase();
  if (isValidAccountType(normalized)) {
    return normalized;
  }
  console.warn(`Unknown account type: "${type}", using fallback: "${fallback}"`);
  return fallback;
}

// GraphQL Queries
const ACCOUNTS_QUERY = gql`
  query Accounts($companyId: ID!) {
    accounts(companyId: $companyId) {
      id
      companyId
      accountNumber
      name
      accountType
      parentId
      description
      vatCodeId
      isActive
      isSystemAccount
      standardAccountNumber
      createdAt
      updatedAt
    }
  }
`;

const ACTIVE_ACCOUNTS_QUERY = gql`
  query ActiveAccounts($companyId: ID!) {
    activeAccounts(companyId: $companyId) {
      id
      companyId
      accountNumber
      name
      accountType
      parentId
      description
      vatCodeId
      isActive
      isSystemAccount
      standardAccountNumber
      createdAt
      updatedAt
    }
  }
`;

// Response types - map backend AccountType to frontend type
interface AccountResponse {
  id: string;
  companyId: string;
  accountNumber: string;
  name: string;
  accountType: string;
  parentId?: string;
  description?: string;
  vatCodeId?: string;
  isActive: boolean;
  isSystemAccount: boolean;
  /** Erhvervsstyrelsens standardkontonummer for SAF-T rapportering */
  standardAccountNumber?: string;
  createdAt: string;
  updatedAt: string;
}

interface AccountsResponse {
  accounts: AccountResponse[];
}

interface ActiveAccountsResponse {
  activeAccounts: AccountResponse[];
}

// Transform backend account type to frontend type
function transformAccount(acc: AccountResponse): Account {
  return {
    id: acc.id,
    companyId: acc.companyId,
    accountNumber: acc.accountNumber,
    name: acc.name,
    type: parseAccountType(acc.accountType),
    parentId: acc.parentId,
    description: acc.description,
    vatCode: acc.vatCodeId,
    isActive: acc.isActive,
    isSystemAccount: acc.isSystemAccount,
    balance: 0, // Not returned from backend yet
    createdAt: acc.createdAt,
    updatedAt: acc.updatedAt,
  };
}

/**
 * Hook to fetch all accounts for a company.
 */
export function useAccounts(
  companyId: string | undefined,
  options?: Omit<UseQueryOptions<Account[], Error>, 'queryKey' | 'queryFn'>
) {
  return useQuery({
    queryKey: createQueryKey('accounts', { companyId }),
    queryFn: async () => {
      if (!companyId) return [];
      const data = await fetchGraphQL<AccountsResponse>(ACCOUNTS_QUERY, { companyId });
      return data.accounts.map(transformAccount);
    },
    enabled: !!companyId,
    ...options,
  });
}

/**
 * Hook to fetch active accounts for a company.
 */
export function useActiveAccounts(
  companyId: string | undefined,
  options?: Omit<UseQueryOptions<Account[], Error>, 'queryKey' | 'queryFn'>
) {
  return useQuery({
    queryKey: createQueryKey('activeAccounts', { companyId }),
    queryFn: async () => {
      if (!companyId) return [];
      const data = await fetchGraphQL<ActiveAccountsResponse>(ACTIVE_ACCOUNTS_QUERY, {
        companyId,
      });
      return data.activeAccounts.map(transformAccount);
    },
    enabled: !!companyId,
    ...options,
  });
}

// =====================================================================
// ACCOUNT BALANCES WITH PERIOD FILTERING (from Ledger service)
// =====================================================================

const ACCOUNT_BALANCES_QUERY = gql`
  query AccountBalances($companyId: ID!, $fromDate: DateTime, $toDate: DateTime) {
    accountBalances(companyId: $companyId, fromDate: $fromDate, toDate: $toDate) {
      id
      accountNumber
      name
      accountType
      isActive
      totalDebits
      totalCredits
      netChange
      entryCount
    }
  }
`;

interface AccountBalanceResponse {
  id: string;
  accountNumber: string;
  name: string;
  accountType: string;
  isActive: boolean;
  totalDebits: number;
  totalCredits: number;
  netChange: number;
  entryCount: number;
}

interface AccountBalancesResponse {
  accountBalances: AccountBalanceResponse[];
}

function transformAccountBalance(resp: AccountBalanceResponse): AccountBalance {
  return {
    id: resp.id,
    accountNumber: resp.accountNumber,
    name: resp.name,
    accountType: parseAccountType(resp.accountType),
    isActive: resp.isActive,
    totalDebits: resp.totalDebits,
    totalCredits: resp.totalCredits,
    netChange: resp.netChange,
    entryCount: resp.entryCount,
  };
}

export interface DateRange {
  startDate: Dayjs;
  endDate: Dayjs;
}

/**
 * Hook to fetch account balances for a company within a specific date range.
 * Uses the Ledger service's QueryEntriesAsync with Aggregate=true.
 */
export function useAccountBalances(
  companyId: string | undefined,
  dateRange?: DateRange,
  options?: Omit<UseQueryOptions<AccountBalance[], Error>, 'queryKey' | 'queryFn'>
) {
  return useQuery({
    queryKey: createQueryKey('accountBalances', {
      companyId,
      // Use format() to avoid UTC conversion shifting the date
      fromDate: dateRange?.startDate?.format('YYYY-MM-DDTHH:mm:ss'),
      toDate: dateRange?.endDate?.format('YYYY-MM-DDTHH:mm:ss'),
    }),
    queryFn: async () => {
      if (!companyId) return [];
      const data = await fetchGraphQL<AccountBalancesResponse>(ACCOUNT_BALANCES_QUERY, {
        companyId,
        // Use format() to avoid UTC conversion shifting the date
        fromDate: dateRange?.startDate?.format('YYYY-MM-DDTHH:mm:ss'),
        toDate: dateRange?.endDate?.format('YYYY-MM-DDTHH:mm:ss'),
      });
      return data.accountBalances.map(transformAccountBalance);
    },
    enabled: !!companyId,
    ...options,
  });
}
