import { useQuery, UseQueryOptions } from '@tanstack/react-query';
import { gql } from 'graphql-request';
import { fetchGraphQL, createQueryKey } from '../client';

// GraphQL Queries
const INVOICES_QUERY = gql`
  query Invoices($companyId: ID!, $status: String) {
    invoices(companyId: $companyId, status: $status) {
      id
      companyId
      fiscalYearId
      customerId
      customerName
      customerNumber
      invoiceNumber
      invoiceType
      isCreditNote
      originalInvoiceId
      originalInvoiceNumber
      creditReason
      invoiceDate
      dueDate
      status
      amountExVat
      amountVat
      amountTotal
      amountPaid
      amountApplied
      amountRemaining
      currency
      vatCode
      paymentTermsDays
      ledgerTransactionId
      notes
      reference
      sentAt
      issuedAt
      paidAt
      voidedAt
      voidedReason
      voidedBy
      createdBy
      updatedBy
      createdAt
      updatedAt
      lines {
        lineNumber
        description
        quantity
        unit
        unitPrice
        discountPercent
        vatCode
        accountId
        amountExVat
        amountVat
        amountTotal
      }
    }
  }
`;

const INVOICE_QUERY = gql`
  query Invoice($id: ID!) {
    invoice(id: $id) {
      id
      companyId
      fiscalYearId
      customerId
      customerName
      customerNumber
      invoiceNumber
      invoiceType
      isCreditNote
      originalInvoiceId
      originalInvoiceNumber
      creditReason
      invoiceDate
      dueDate
      status
      amountExVat
      amountVat
      amountTotal
      amountPaid
      amountApplied
      amountRemaining
      currency
      vatCode
      paymentTermsDays
      ledgerTransactionId
      notes
      reference
      sentAt
      issuedAt
      paidAt
      voidedAt
      voidedReason
      voidedBy
      createdBy
      updatedBy
      createdAt
      updatedAt
      lines {
        lineNumber
        description
        quantity
        unit
        unitPrice
        discountPercent
        vatCode
        accountId
        amountExVat
        amountVat
        amountTotal
      }
    }
  }
`;

const INVOICES_BY_CUSTOMER_QUERY = gql`
  query InvoicesByCustomer($customerId: ID!) {
    invoicesByCustomer(customerId: $customerId) {
      id
      companyId
      invoiceNumber
      invoiceDate
      dueDate
      status
      amountTotal
      amountPaid
      amountRemaining
      customerName
    }
  }
`;

// Credit note queries (via unified Invoice model)
const CREDIT_NOTES_QUERY = gql`
  query CreditNotes($companyId: ID!) {
    creditNotes(companyId: $companyId) {
      id
      companyId
      fiscalYearId
      customerId
      customerName
      customerNumber
      invoiceNumber
      invoiceType
      isCreditNote
      originalInvoiceId
      originalInvoiceNumber
      creditReason
      invoiceDate
      dueDate
      status
      amountExVat
      amountVat
      amountTotal
      amountPaid
      amountApplied
      amountRemaining
      currency
      vatCode
      ledgerTransactionId
      notes
      reference
      sentAt
      issuedAt
      paidAt
      voidedAt
      voidedReason
      createdBy
      createdAt
      updatedAt
      lines {
        lineNumber
        description
        quantity
        unit
        unitPrice
        discountPercent
        vatCode
        accountId
        amountExVat
        amountVat
        amountTotal
      }
    }
  }
`;

const UNAPPLIED_CREDIT_NOTES_QUERY = gql`
  query UnappliedCreditNotes($companyId: ID!) {
    unappliedCreditNotes(companyId: $companyId) {
      id
      companyId
      customerId
      customerName
      invoiceNumber
      invoiceDate
      amountTotal
      amountApplied
      amountRemaining
    }
  }
`;

// Types
export type InvoiceStatus = 'draft' | 'sent' | 'issued' | 'partially_paid' | 'partially_applied' | 'paid' | 'fully_applied' | 'voided';
export type InvoiceDocumentType = 'invoice' | 'credit_note';

export interface InvoiceLine {
  lineNumber: number;
  description: string;
  quantity: number;
  unit?: string;
  unitPrice: number;
  discountPercent: number;
  vatCode: string;
  accountId?: string;
  amountExVat: number;
  amountVat: number;
  amountTotal: number;
}

export interface Invoice {
  id: string;
  companyId: string;
  fiscalYearId?: string;
  customerId: string;
  customerName: string;
  customerNumber: string;
  invoiceNumber: string;
  // Document type fields (for credit note support)
  invoiceType: InvoiceDocumentType;
  isCreditNote: boolean;
  originalInvoiceId?: string;
  originalInvoiceNumber?: string;
  creditReason?: string;
  // Dates
  invoiceDate?: string;
  dueDate?: string;
  // Status and amounts
  status: InvoiceStatus;
  amountExVat: number;
  amountVat: number;
  amountTotal: number;
  amountPaid: number;
  amountApplied: number;  // For credit notes
  amountRemaining: number;
  currency: string;
  vatCode?: string;
  paymentTermsDays: number;
  ledgerTransactionId?: string;
  notes?: string;
  reference?: string;
  sentAt?: string;
  issuedAt?: string;  // For credit notes
  paidAt?: string;
  voidedAt?: string;
  voidedReason?: string;
  voidedBy?: string;
  createdBy: string;
  updatedBy?: string;
  createdAt: string;
  updatedAt: string;
  lines: InvoiceLine[];
}

// Response types
interface InvoicesResponse {
  invoices: Invoice[];
}

interface InvoiceResponse {
  invoice: Invoice;
}

interface InvoicesByCustomerResponse {
  invoicesByCustomer: Invoice[];
}

/**
 * Hook to fetch invoices for a company with optional status filter.
 */
export function useInvoices(
  companyId: string | undefined,
  filters?: { status?: InvoiceStatus },
  options?: Omit<UseQueryOptions<Invoice[], Error>, 'queryKey' | 'queryFn'>
) {
  return useQuery({
    queryKey: createQueryKey('invoices', { companyId, ...filters }),
    queryFn: async () => {
      if (!companyId) return [];
      const data = await fetchGraphQL<InvoicesResponse>(INVOICES_QUERY, {
        companyId,
        status: filters?.status,
      });
      return data.invoices;
    },
    enabled: !!companyId,
    ...options,
  });
}

/**
 * Hook to fetch a single invoice by ID.
 */
export function useInvoice(
  id: string | undefined,
  options?: Omit<UseQueryOptions<Invoice | null, Error>, 'queryKey' | 'queryFn'>
) {
  return useQuery({
    queryKey: createQueryKey('invoice', { id }),
    queryFn: async () => {
      if (!id) return null;
      const data = await fetchGraphQL<InvoiceResponse>(INVOICE_QUERY, { id });
      return data.invoice;
    },
    enabled: !!id,
    ...options,
  });
}

/**
 * Hook to fetch invoices by customer.
 */
export function useInvoicesByCustomer(
  customerId: string | undefined,
  options?: Omit<UseQueryOptions<Invoice[], Error>, 'queryKey' | 'queryFn'>
) {
  return useQuery({
    queryKey: createQueryKey('invoicesByCustomer', { customerId }),
    queryFn: async () => {
      if (!customerId) return [];
      const data = await fetchGraphQL<InvoicesByCustomerResponse>(INVOICES_BY_CUSTOMER_QUERY, {
        customerId,
      });
      return data.invoicesByCustomer;
    },
    enabled: !!customerId,
    ...options,
  });
}

// =====================================================
// CREDIT NOTE HOOKS (via unified Invoice model)
// =====================================================

interface CreditNotesResponse {
  creditNotes: Invoice[];
}

interface UnappliedCreditNotesResponse {
  unappliedCreditNotes: Invoice[];
}

/**
 * Hook to fetch all credit notes for a company.
 * Credit notes are invoices with invoiceType = 'credit_note'.
 */
export function useCreditNotes(
  companyId: string | undefined,
  options?: Omit<UseQueryOptions<Invoice[], Error>, 'queryKey' | 'queryFn'>
) {
  return useQuery({
    queryKey: createQueryKey('creditNotes', { companyId }),
    queryFn: async () => {
      if (!companyId) return [];
      const data = await fetchGraphQL<CreditNotesResponse>(CREDIT_NOTES_QUERY, { companyId });
      return data.creditNotes;
    },
    enabled: !!companyId,
    ...options,
  });
}

/**
 * Hook to fetch unapplied credit notes (with remaining balance).
 */
export function useUnappliedCreditNotes(
  companyId: string | undefined,
  options?: Omit<UseQueryOptions<Invoice[], Error>, 'queryKey' | 'queryFn'>
) {
  return useQuery({
    queryKey: createQueryKey('unappliedCreditNotes', { companyId }),
    queryFn: async () => {
      if (!companyId) return [];
      const data = await fetchGraphQL<UnappliedCreditNotesResponse>(UNAPPLIED_CREDIT_NOTES_QUERY, {
        companyId,
      });
      return data.unappliedCreditNotes;
    },
    enabled: !!companyId,
    ...options,
  });
}
