/**
 * Xero Invoice Tools
 * Handles invoices (AR invoices), line items, and invoice-related operations
 */

import { z } from 'zod';
import { XeroClient } from '../clients/xero.js';
import type { Tool } from '@modelcontextprotocol/sdk/types.js';

const LineItemSchema = z.object({
  Description: z.string().optional(),
  Quantity: z.number().optional(),
  UnitAmount: z.number().optional(),
  ItemCode: z.string().optional(),
  AccountCode: z.string().optional(),
  TaxType: z.string().optional(),
  DiscountRate: z.number().optional(),
  LineAmount: z.number().optional()
});

const ContactSchema = z.object({
  ContactID: z.string().optional(),
  ContactNumber: z.string().optional(),
  Name: z.string().optional()
});

export function getTools(_client: XeroClient): Tool[] {
  return [
    // List invoices
    {
      name: 'xero_list_invoices',
      description: 'List all invoices with optional filtering. Use where clause for filtering (e.g., Status=="AUTHORISED" or Type=="ACCREC")',
      inputSchema: {
        type: 'object',
        properties: {
          page: { type: 'number', description: 'Page number (default 1)' },
          pageSize: { type: 'number', description: 'Page size (max 100, default 100)' },
          where: { type: 'string', description: 'Filter expression (e.g., Status=="AUTHORISED")' },
          order: { type: 'string', description: 'Order by field (e.g., InvoiceNumber DESC)' },
          includeArchived: { type: 'boolean', description: 'Include archived records' },
          ifModifiedSince: { type: 'string', description: 'ISO date to get only records modified since' }
        }
      }
    },

    // Get single invoice
    {
      name: 'xero_get_invoice',
      description: 'Get a specific invoice by ID. Returns full invoice details including line items.',
      inputSchema: {
        type: 'object',
        properties: {
          invoiceId: { type: 'string', description: 'Invoice ID (GUID)' }
        },
        required: ['invoiceId']
      }
    },

    // Create invoice
    {
      name: 'xero_create_invoice',
      description: 'Create a new invoice (AR invoice). Type defaults to ACCREC (accounts receivable). Status can be DRAFT or AUTHORISED.',
      inputSchema: {
        type: 'object',
        properties: {
          type: { 
            type: 'string', 
            enum: ['ACCREC', 'ACCPAY'],
            description: 'ACCREC for AR invoice, ACCPAY for AP invoice/bill (default: ACCREC)' 
          },
          contact: {
            type: 'object',
            properties: {
              ContactID: { type: 'string', description: 'Contact ID (GUID)' },
              ContactNumber: { type: 'string', description: 'Contact number' },
              Name: { type: 'string', description: 'Contact name' }
            },
            description: 'Contact (must include ContactID or Name)'
          },
          lineItems: {
            type: 'array',
            items: {
              type: 'object',
              properties: {
                Description: { type: 'string' },
                Quantity: { type: 'number' },
                UnitAmount: { type: 'number' },
                ItemCode: { type: 'string' },
                AccountCode: { type: 'string' },
                TaxType: { type: 'string' },
                DiscountRate: { type: 'number' },
                LineAmount: { type: 'number' }
              }
            },
            description: 'Line items (at least one required)'
          },
          date: { type: 'string', description: 'Invoice date (YYYY-MM-DD)' },
          dueDate: { type: 'string', description: 'Due date (YYYY-MM-DD)' },
          reference: { type: 'string', description: 'Reference text' },
          invoiceNumber: { type: 'string', description: 'Invoice number (optional, auto-generated if omitted)' },
          status: { 
            type: 'string', 
            enum: ['DRAFT', 'AUTHORISED'],
            description: 'Invoice status (default: DRAFT)' 
          },
          lineAmountTypes: {
            type: 'string',
            enum: ['Exclusive', 'Inclusive', 'NoTax'],
            description: 'How line amounts are calculated (default: Exclusive)'
          },
          currencyCode: { type: 'string', description: 'Currency code (e.g., USD, GBP)' }
        },
        required: ['contact', 'lineItems']
      }
    },

    // Update invoice
    {
      name: 'xero_update_invoice',
      description: 'Update an existing invoice. Can update status, reference, due date, and other fields.',
      inputSchema: {
        type: 'object',
        properties: {
          invoiceId: { type: 'string', description: 'Invoice ID (GUID)' },
          status: { 
            type: 'string',
            enum: ['DRAFT', 'AUTHORISED', 'SUBMITTED'],
            description: 'New status' 
          },
          reference: { type: 'string', description: 'Reference text' },
          dueDate: { type: 'string', description: 'Due date (YYYY-MM-DD)' },
          lineItems: {
            type: 'array',
            items: {
              type: 'object',
              properties: {
                Description: { type: 'string' },
                Quantity: { type: 'number' },
                UnitAmount: { type: 'number' },
                AccountCode: { type: 'string' },
                TaxType: { type: 'string' }
              }
            },
            description: 'Updated line items (replaces all existing line items)'
          }
        },
        required: ['invoiceId']
      }
    },

    // Void invoice
    {
      name: 'xero_void_invoice',
      description: 'Void an invoice. This sets the status to VOIDED. Cannot be undone.',
      inputSchema: {
        type: 'object',
        properties: {
          invoiceId: { type: 'string', description: 'Invoice ID (GUID)' }
        },
        required: ['invoiceId']
      }
    },

    // Delete invoice
    {
      name: 'xero_delete_invoice',
      description: 'Delete a DRAFT invoice. Only DRAFT invoices can be deleted.',
      inputSchema: {
        type: 'object',
        properties: {
          invoiceId: { type: 'string', description: 'Invoice ID (GUID)' }
        },
        required: ['invoiceId']
      }
    },

    // Email invoice
    {
      name: 'xero_email_invoice',
      description: 'Email an invoice to the contact. The invoice must be AUTHORISED.',
      inputSchema: {
        type: 'object',
        properties: {
          invoiceId: { type: 'string', description: 'Invoice ID (GUID)' }
        },
        required: ['invoiceId']
      }
    },

    // Create invoice attachment
    {
      name: 'xero_add_invoice_attachment',
      description: 'Add an attachment to an invoice. Supported file types: PDF, PNG, JPG, GIF, etc.',
      inputSchema: {
        type: 'object',
        properties: {
          invoiceId: { type: 'string', description: 'Invoice ID (GUID)' },
          fileName: { type: 'string', description: 'File name including extension' },
          mimeType: { type: 'string', description: 'MIME type (e.g., application/pdf)' },
          content: { type: 'string', description: 'Base64-encoded file content' }
        },
        required: ['invoiceId', 'fileName', 'mimeType', 'content']
      }
    },

    // Get invoice attachments
    {
      name: 'xero_get_invoice_attachments',
      description: 'Get all attachments for an invoice.',
      inputSchema: {
        type: 'object',
        properties: {
          invoiceId: { type: 'string', description: 'Invoice ID (GUID)' }
        },
        required: ['invoiceId']
      }
    }
  ];
}

export async function handleInvoiceTool(
  toolName: string,
  args: Record<string, unknown>,
  client: XeroClient
): Promise<unknown> {
  switch (toolName) {
    case 'xero_list_invoices': {
      const options = {
        page: args.page as number | undefined,
        pageSize: args.pageSize as number | undefined,
        where: args.where as string | undefined,
        order: args.order as string | undefined,
        includeArchived: args.includeArchived as boolean | undefined,
        ifModifiedSince: args.ifModifiedSince ? new Date(args.ifModifiedSince as string) : undefined
      };
      return await client.getInvoices(options);
    }

    case 'xero_get_invoice': {
      const { invoiceId } = z.object({ invoiceId: z.string() }).parse(args);
      return await client.getInvoice(invoiceId as any);
    }

    case 'xero_create_invoice': {
      const schema = z.object({
        type: z.enum(['ACCREC', 'ACCPAY']).default('ACCREC'),
        contact: ContactSchema,
        lineItems: z.array(LineItemSchema).min(1),
        date: z.string().optional(),
        dueDate: z.string().optional(),
        reference: z.string().optional(),
        invoiceNumber: z.string().optional(),
        status: z.enum(['DRAFT', 'AUTHORISED']).default('DRAFT'),
        lineAmountTypes: z.enum(['Exclusive', 'Inclusive', 'NoTax']).default('Exclusive'),
        currencyCode: z.string().optional()
      });
      const data = schema.parse(args);
      
      const invoice: any = {
        Type: data.type,
        Contact: data.contact,
        LineItems: data.lineItems,
        Status: data.status,
        LineAmountTypes: data.lineAmountTypes
      };
      
      if (data.date) invoice.Date = data.date;
      if (data.dueDate) invoice.DueDate = data.dueDate;
      if (data.reference) invoice.Reference = data.reference;
      if (data.invoiceNumber) invoice.InvoiceNumber = data.invoiceNumber;
      if (data.currencyCode) invoice.CurrencyCode = data.currencyCode;
      
      return await client.createInvoice(invoice);
    }

    case 'xero_update_invoice': {
      const schema = z.object({
        invoiceId: z.string(),
        status: z.enum(['DRAFT', 'AUTHORISED', 'SUBMITTED']).optional(),
        reference: z.string().optional(),
        dueDate: z.string().optional(),
        lineItems: z.array(LineItemSchema).optional()
      });
      const data = schema.parse(args);
      
      const updates: any = {};
      if (data.status) updates.Status = data.status;
      if (data.reference) updates.Reference = data.reference;
      if (data.dueDate) updates.DueDate = data.dueDate;
      if (data.lineItems) updates.LineItems = data.lineItems;
      
      return await client.updateInvoice(data.invoiceId as any, updates);
    }

    case 'xero_void_invoice': {
      const { invoiceId } = z.object({ invoiceId: z.string() }).parse(args);
      return await client.updateInvoice(invoiceId as any, { Status: 'VOIDED' as any });
    }

    case 'xero_delete_invoice': {
      const { invoiceId } = z.object({ invoiceId: z.string() }).parse(args);
      await client.deleteInvoice(invoiceId as any);
      return { success: true, message: 'Invoice deleted' };
    }

    case 'xero_email_invoice': {
      const { invoiceId } = z.object({ invoiceId: z.string() }).parse(args);
      // Xero doesn't have a direct email endpoint; this is typically done via the UI
      // or a separate request. For now, we'll just verify the invoice exists and is AUTHORISED.
      const invoice = await client.getInvoice(invoiceId as any);
      if ((invoice as any).Status !== 'AUTHORISED') {
        throw new Error('Invoice must be AUTHORISED to be emailed');
      }
      return { 
        success: true, 
        message: 'Invoice is AUTHORISED and ready to email. Use Xero UI or direct API call to send.',
        invoiceUrl: (invoice as any).Url 
      };
    }

    case 'xero_add_invoice_attachment': {
      const schema = z.object({
        invoiceId: z.string(),
        fileName: z.string(),
        mimeType: z.string(),
        content: z.string()
      });
      const data = schema.parse(args);
      
      const buffer = Buffer.from(data.content, 'base64');
      return await client.uploadAttachment('Invoices', data.invoiceId, data.fileName, buffer, data.mimeType);
    }

    case 'xero_get_invoice_attachments': {
      const { invoiceId } = z.object({ invoiceId: z.string() }).parse(args);
      return await client.getAttachments('Invoices', invoiceId);
    }

    default:
      throw new Error(`Unknown invoice tool: ${toolName}`);
  }
}
