import { useMutation, useQueryClient } from '@tanstack/react-query';
import { gql } from 'graphql-request';
import { fetchGraphQL, createQueryKey } from '../client';
import type { Invoice } from '../queries/invoiceQueries';

// GraphQL Mutations
const CREATE_INVOICE_MUTATION = gql`
  mutation CreateInvoice($input: CreateInvoiceInput!) {
    createInvoice(input: $input) {
      id
      companyId
      customerId
      customerName
      invoiceNumber
      invoiceDate
      dueDate
      status
      amountExVat
      amountVat
      amountTotal
      amountPaid
      amountRemaining
      paymentTermsDays
      notes
      reference
      createdAt
      updatedAt
      lines {
        lineNumber
        description
        quantity
        unit
        unitPrice
        discountPercent
        vatCode
        accountId
        amountExVat
        amountVat
        amountTotal
      }
    }
  }
`;

const ADD_INVOICE_LINE_MUTATION = gql`
  mutation AddInvoiceLine($input: AddInvoiceLineInput!) {
    addInvoiceLine(input: $input) {
      id
      companyId
      customerId
      amountExVat
      amountVat
      amountTotal
      updatedAt
      lines {
        lineNumber
        description
        quantity
        unit
        unitPrice
        discountPercent
        vatCode
        accountId
        amountExVat
        amountVat
        amountTotal
      }
    }
  }
`;

const UPDATE_INVOICE_LINE_MUTATION = gql`
  mutation UpdateInvoiceLine($input: UpdateInvoiceLineInput!) {
    updateInvoiceLine(input: $input) {
      id
      companyId
      customerId
      amountExVat
      amountVat
      amountTotal
      updatedAt
      lines {
        lineNumber
        description
        quantity
        unit
        unitPrice
        discountPercent
        vatCode
        accountId
        amountExVat
        amountVat
        amountTotal
      }
    }
  }
`;

const REMOVE_INVOICE_LINE_MUTATION = gql`
  mutation RemoveInvoiceLine($invoiceId: ID!, $lineNumber: Int!) {
    removeInvoiceLine(invoiceId: $invoiceId, lineNumber: $lineNumber) {
      id
      companyId
      customerId
      amountExVat
      amountVat
      amountTotal
      updatedAt
      lines {
        lineNumber
        description
        quantity
        unit
        unitPrice
        discountPercent
        vatCode
        accountId
        amountExVat
        amountVat
        amountTotal
      }
    }
  }
`;

const SEND_INVOICE_MUTATION = gql`
  mutation SendInvoice($id: ID!) {
    sendInvoice(id: $id) {
      id
      companyId
      customerId
      status
      ledgerTransactionId
      sentAt
      updatedAt
    }
  }
`;

const RECEIVE_PAYMENT_MUTATION = gql`
  mutation ReceivePayment($input: ReceivePaymentInput!) {
    receivePayment(input: $input) {
      id
      companyId
      customerId
      status
      amountPaid
      amountRemaining
      paidAt
      updatedAt
    }
  }
`;

const VOID_INVOICE_MUTATION = gql`
  mutation VoidInvoice($input: VoidInvoiceInput!) {
    voidInvoice(input: $input) {
      id
      companyId
      customerId
      status
      voidedAt
      voidedReason
      voidedBy
      updatedAt
    }
  }
`;

// Input types
export interface CreateInvoiceInput {
  companyId: string;
  fiscalYearId: string;
  customerId: string;
  invoiceDate?: string;
  dueDate?: string;
  vatCode?: string;
  notes?: string;
  reference?: string;
  // Note: paymentTermsDays is NOT an input field - it's derived from customer's default payment terms
}

export interface AddInvoiceLineInput {
  invoiceId: string;
  description: string;
  quantity: number;
  unitPrice: number;
  unit?: string;
  discountPercent?: number;
  vatCode?: string;
  accountId?: string;
}

export interface UpdateInvoiceLineInput {
  invoiceId: string;
  lineNumber: number;
  description: string;    // Required by backend
  quantity: number;       // Required by backend
  unitPrice: number;      // Required by backend
  unit?: string;
  discountPercent?: number;
  vatCode?: string;
  accountId?: string;
}

export interface ReceivePaymentInput {
  invoiceId: string;
  amount: number;
  bankAccountId: string;
  bankTransactionId?: string;
  paymentReference?: string;
  paymentDate?: string;
}

export interface VoidInvoiceInput {
  invoiceId: string;
  reason: string;
}

// Response types
interface CreateInvoiceResponse {
  createInvoice: Invoice;
}

interface AddInvoiceLineResponse {
  addInvoiceLine: Invoice;
}

interface UpdateInvoiceLineResponse {
  updateInvoiceLine: Invoice;
}

interface RemoveInvoiceLineResponse {
  removeInvoiceLine: Invoice;
}

interface SendInvoiceResponse {
  sendInvoice: Invoice;
}

interface ReceivePaymentResponse {
  receivePayment: Invoice;
}

interface VoidInvoiceResponse {
  voidInvoice: Invoice;
}

/**
 * Hook to create a new invoice (draft).
 */
export function useCreateInvoice() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async (input: CreateInvoiceInput) => {
      const data = await fetchGraphQL<CreateInvoiceResponse>(CREATE_INVOICE_MUTATION, { input });
      return data.createInvoice;
    },
    onSuccess: (data) => {
      queryClient.invalidateQueries({
        queryKey: createQueryKey('invoices', { companyId: data.companyId }),
      });
      queryClient.invalidateQueries({
        queryKey: createQueryKey('invoicesByCustomer', { customerId: data.customerId }),
      });
    },
  });
}

/**
 * Hook to add a line to an invoice.
 */
export function useAddInvoiceLine() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async (input: AddInvoiceLineInput) => {
      const data = await fetchGraphQL<AddInvoiceLineResponse>(ADD_INVOICE_LINE_MUTATION, { input });
      return data.addInvoiceLine;
    },
    onSuccess: (data) => {
      queryClient.setQueryData(createQueryKey('invoice', { id: data.id }), data);
      queryClient.invalidateQueries({
        queryKey: createQueryKey('invoices', { companyId: data.companyId }),
      });
      queryClient.invalidateQueries({
        queryKey: createQueryKey('invoicesByCustomer', { customerId: data.customerId }),
      });
    },
  });
}

/**
 * Hook to update an invoice line.
 */
export function useUpdateInvoiceLine() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async (input: UpdateInvoiceLineInput) => {
      const data = await fetchGraphQL<UpdateInvoiceLineResponse>(UPDATE_INVOICE_LINE_MUTATION, { input });
      return data.updateInvoiceLine;
    },
    onSuccess: (data) => {
      queryClient.setQueryData(createQueryKey('invoice', { id: data.id }), data);
      queryClient.invalidateQueries({
        queryKey: createQueryKey('invoices', { companyId: data.companyId }),
      });
      queryClient.invalidateQueries({
        queryKey: createQueryKey('invoicesByCustomer', { customerId: data.customerId }),
      });
    },
  });
}

/**
 * Hook to remove an invoice line.
 */
export function useRemoveInvoiceLine() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async ({ invoiceId, lineNumber }: { invoiceId: string; lineNumber: number }) => {
      const data = await fetchGraphQL<RemoveInvoiceLineResponse>(REMOVE_INVOICE_LINE_MUTATION, {
        invoiceId,
        lineNumber,
      });
      return data.removeInvoiceLine;
    },
    onSuccess: (data) => {
      queryClient.setQueryData(createQueryKey('invoice', { id: data.id }), data);
      queryClient.invalidateQueries({
        queryKey: createQueryKey('invoices', { companyId: data.companyId }),
      });
      queryClient.invalidateQueries({
        queryKey: createQueryKey('invoicesByCustomer', { customerId: data.customerId }),
      });
    },
  });
}

/**
 * Hook to send an invoice (posts to ledger).
 */
export function useSendInvoice() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async (id: string) => {
      const data = await fetchGraphQL<SendInvoiceResponse>(SEND_INVOICE_MUTATION, { id });
      return data.sendInvoice;
    },
    onSuccess: (data) => {
      queryClient.invalidateQueries({
        queryKey: createQueryKey('invoice', { id: data.id }),
      });
      queryClient.invalidateQueries({
        queryKey: createQueryKey('invoices', { companyId: data.companyId }),
      });
      queryClient.invalidateQueries({
        queryKey: createQueryKey('invoicesByCustomer', { customerId: data.customerId }),
      });
    },
  });
}

/**
 * Hook to receive a payment for an invoice.
 */
export function useReceivePayment() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async (input: ReceivePaymentInput) => {
      const data = await fetchGraphQL<ReceivePaymentResponse>(RECEIVE_PAYMENT_MUTATION, { input });
      return data.receivePayment;
    },
    onSuccess: (data) => {
      queryClient.invalidateQueries({
        queryKey: createQueryKey('invoice', { id: data.id }),
      });
      queryClient.invalidateQueries({
        queryKey: createQueryKey('invoices', { companyId: data.companyId }),
      });
      queryClient.invalidateQueries({
        queryKey: createQueryKey('invoicesByCustomer', { customerId: data.customerId }),
      });
      // Payment affects customer balance
      queryClient.invalidateQueries({
        queryKey: createQueryKey('customerBalance', { customerId: data.customerId }),
      });
    },
  });
}

/**
 * Hook to void an invoice.
 */
export function useVoidInvoice() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async (input: VoidInvoiceInput) => {
      const data = await fetchGraphQL<VoidInvoiceResponse>(VOID_INVOICE_MUTATION, { input });
      return data.voidInvoice;
    },
    onSuccess: (data) => {
      queryClient.invalidateQueries({
        queryKey: createQueryKey('invoice', { id: data.id }),
      });
      queryClient.invalidateQueries({
        queryKey: createQueryKey('invoices', { companyId: data.companyId }),
      });
      queryClient.invalidateQueries({
        queryKey: createQueryKey('invoicesByCustomer', { customerId: data.customerId }),
      });
      // Voiding affects customer balance
      queryClient.invalidateQueries({
        queryKey: createQueryKey('customerBalance', { customerId: data.customerId }),
      });
    },
  });
}

// =====================================================
// CREDIT NOTE MUTATIONS
// =====================================================

const CREATE_CREDIT_NOTE_MUTATION = gql`
  mutation CreateCreditNote($input: CreateCreditNoteInput!) {
    createCreditNote(input: $input) {
      id
      companyId
      fiscalYearId
      customerId
      customerName
      customerNumber
      invoiceNumber
      invoiceType
      isCreditNote
      originalInvoiceId
      originalInvoiceNumber
      creditReason
      invoiceDate
      status
      amountExVat
      amountVat
      amountTotal
      amountApplied
      amountRemaining
      notes
      reference
      createdAt
      updatedAt
      lines {
        lineNumber
        description
        quantity
        unit
        unitPrice
        discountPercent
        vatCode
        accountId
        amountExVat
        amountVat
        amountTotal
      }
    }
  }
`;

const ISSUE_CREDIT_NOTE_MUTATION = gql`
  mutation IssueCreditNote($id: ID!) {
    issueCreditNote(id: $id) {
      id
      companyId
      customerId
      status
      ledgerTransactionId
      issuedAt
      updatedAt
    }
  }
`;

const APPLY_CREDIT_NOTE_MUTATION = gql`
  mutation ApplyCreditNote($input: ApplyCreditNoteInput!) {
    applyCreditNote(input: $input) {
      id
      companyId
      customerId
      status
      amountApplied
      amountRemaining
      updatedAt
    }
  }
`;

// Credit note input types
export interface CreateCreditNoteInput {
  companyId: string;
  fiscalYearId: string;
  customerId: string;
  creditNoteDate?: string;
  originalInvoiceId?: string;
  creditReason?: string;
  vatCode?: string;
  notes?: string;
  reference?: string;
}

export interface ApplyCreditNoteInput {
  creditNoteId: string;
  invoiceId: string;
  amount: number;
}

// Credit note response types
interface CreateCreditNoteResponse {
  createCreditNote: Invoice;
}

interface IssueCreditNoteResponse {
  issueCreditNote: Invoice;
}

interface ApplyCreditNoteResponse {
  applyCreditNote: Invoice;
}

/**
 * Hook to create a new credit note (draft).
 */
export function useCreateCreditNote() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async (input: CreateCreditNoteInput) => {
      const data = await fetchGraphQL<CreateCreditNoteResponse>(CREATE_CREDIT_NOTE_MUTATION, { input });
      return data.createCreditNote;
    },
    onSuccess: (data) => {
      queryClient.invalidateQueries({
        queryKey: createQueryKey('creditNotes', { companyId: data.companyId }),
      });
      queryClient.invalidateQueries({
        queryKey: createQueryKey('invoicesByCustomer', { customerId: data.customerId }),
      });
    },
  });
}

/**
 * Hook to issue a credit note (posts to ledger).
 */
export function useIssueCreditNote() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async (id: string) => {
      const data = await fetchGraphQL<IssueCreditNoteResponse>(ISSUE_CREDIT_NOTE_MUTATION, { id });
      return data.issueCreditNote;
    },
    onSuccess: (data) => {
      queryClient.invalidateQueries({
        queryKey: createQueryKey('creditNotes', { companyId: data.companyId }),
      });
      queryClient.invalidateQueries({
        queryKey: createQueryKey('unappliedCreditNotes', { companyId: data.companyId }),
      });
      queryClient.invalidateQueries({
        queryKey: createQueryKey('invoicesByCustomer', { customerId: data.customerId }),
      });
    },
  });
}

/**
 * Hook to apply a credit note to an invoice.
 */
export function useApplyCreditNote() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async (input: ApplyCreditNoteInput) => {
      const data = await fetchGraphQL<ApplyCreditNoteResponse>(APPLY_CREDIT_NOTE_MUTATION, { input });
      return data.applyCreditNote;
    },
    onSuccess: (data) => {
      queryClient.invalidateQueries({
        queryKey: createQueryKey('creditNotes', { companyId: data.companyId }),
      });
      queryClient.invalidateQueries({
        queryKey: createQueryKey('unappliedCreditNotes', { companyId: data.companyId }),
      });
      queryClient.invalidateQueries({
        queryKey: createQueryKey('invoices', { companyId: data.companyId }),
      });
      queryClient.invalidateQueries({
        queryKey: createQueryKey('invoicesByCustomer', { customerId: data.customerId }),
      });
      // Credit application affects customer balance
      queryClient.invalidateQueries({
        queryKey: createQueryKey('customerBalance', { customerId: data.customerId }),
      });
    },
  });
}
