/**
 * Xero MCP Server
 * Provides lazy-loaded tools for Xero Accounting API operations
 */

import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
  Tool
} from '@modelcontextprotocol/sdk/types.js';
import { XeroClient } from './clients/xero.js';
import { getAllTools, handleToolCall as handleTool } from './tools/index.js';

export class XeroMCPServer {
  private server: Server;
  private client: XeroClient;
  private toolsCache: Tool[] | null = null;

  constructor(client: XeroClient) {
    this.client = client;
    this.server = new Server(
      {
        name: 'xero-mcp',
        version: '1.0.0'
      },
      {
        capabilities: {
          tools: {}
        }
      }
    );

    this.setupHandlers();
  }

  private setupHandlers(): void {
    this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
      tools: this.getTools()
    }));

    this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
      const { name, arguments: args } = request.params;

      try {
        const result = await this.handleToolCall(name, args || {});
        return {
          content: [
            {
              type: 'text',
              text: JSON.stringify(result, null, 2)
            }
          ]
        };
      } catch (error) {
        const errorMessage = error instanceof Error ? error.message : String(error);
        return {
          content: [
            {
              type: 'text',
              text: JSON.stringify({ error: errorMessage }, null, 2)
            }
          ],
          isError: true
        };
      }
    });
  }

  private getTools(): Tool[] {
    if (this.toolsCache) {
      return this.toolsCache;
    }

    this.toolsCache = [
      // INVOICES
      {
        name: 'xero_list_invoices',
        description: 'List all invoices with optional filtering',
        inputSchema: {
          type: 'object',
          properties: {
            page: { type: 'number', description: 'Page number (default 1)' },
            pageSize: { type: 'number', description: 'Page size (max 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' }
          }
        }
      },
      {
        name: 'xero_get_invoice',
        description: 'Get a specific invoice by ID',
        inputSchema: {
          type: 'object',
          properties: {
            invoiceId: { type: 'string', description: 'Invoice ID (GUID)' }
          },
          required: ['invoiceId']
        }
      },
      {
        name: 'xero_create_invoice',
        description: 'Create a new invoice',
        inputSchema: {
          type: 'object',
          properties: {
            invoice: {
              type: 'object',
              description: 'Invoice data (Contact, LineItems, Type, etc.)'
            }
          },
          required: ['invoice']
        }
      },
      {
        name: 'xero_update_invoice',
        description: 'Update an existing invoice',
        inputSchema: {
          type: 'object',
          properties: {
            invoiceId: { type: 'string', description: 'Invoice ID (GUID)' },
            invoice: { type: 'object', description: 'Invoice update data' }
          },
          required: ['invoiceId', 'invoice']
        }
      },

      // CONTACTS
      {
        name: 'xero_list_contacts',
        description: 'List all contacts with optional filtering',
        inputSchema: {
          type: 'object',
          properties: {
            page: { type: 'number' },
            pageSize: { type: 'number' },
            where: { type: 'string' },
            order: { type: 'string' },
            includeArchived: { type: 'boolean' }
          }
        }
      },
      {
        name: 'xero_get_contact',
        description: 'Get a specific contact by ID',
        inputSchema: {
          type: 'object',
          properties: {
            contactId: { type: 'string', description: 'Contact ID (GUID)' }
          },
          required: ['contactId']
        }
      },
      {
        name: 'xero_create_contact',
        description: 'Create a new contact',
        inputSchema: {
          type: 'object',
          properties: {
            contact: { type: 'object', description: 'Contact data (Name required)' }
          },
          required: ['contact']
        }
      },
      {
        name: 'xero_update_contact',
        description: 'Update an existing contact',
        inputSchema: {
          type: 'object',
          properties: {
            contactId: { type: 'string' },
            contact: { type: 'object' }
          },
          required: ['contactId', 'contact']
        }
      },

      // ACCOUNTS
      {
        name: 'xero_list_accounts',
        description: 'List all chart of accounts',
        inputSchema: {
          type: 'object',
          properties: {
            where: { type: 'string' },
            order: { type: 'string' }
          }
        }
      },
      {
        name: 'xero_get_account',
        description: 'Get a specific account by ID',
        inputSchema: {
          type: 'object',
          properties: {
            accountId: { type: 'string', description: 'Account ID (GUID)' }
          },
          required: ['accountId']
        }
      },
      {
        name: 'xero_create_account',
        description: 'Create a new account',
        inputSchema: {
          type: 'object',
          properties: {
            account: { type: 'object', description: 'Account data (Code, Name, Type required)' }
          },
          required: ['account']
        }
      },

      // BANK TRANSACTIONS
      {
        name: 'xero_list_bank_transactions',
        description: 'List all bank transactions',
        inputSchema: {
          type: 'object',
          properties: {
            page: { type: 'number' },
            pageSize: { type: 'number' },
            where: { type: 'string' },
            order: { type: 'string' }
          }
        }
      },
      {
        name: 'xero_get_bank_transaction',
        description: 'Get a specific bank transaction by ID',
        inputSchema: {
          type: 'object',
          properties: {
            bankTransactionId: { type: 'string' }
          },
          required: ['bankTransactionId']
        }
      },
      {
        name: 'xero_create_bank_transaction',
        description: 'Create a new bank transaction',
        inputSchema: {
          type: 'object',
          properties: {
            transaction: { type: 'object' }
          },
          required: ['transaction']
        }
      },

      // PAYMENTS
      {
        name: 'xero_list_payments',
        description: 'List all payments',
        inputSchema: {
          type: 'object',
          properties: {
            page: { type: 'number' },
            pageSize: { type: 'number' },
            where: { type: 'string' }
          }
        }
      },
      {
        name: 'xero_create_payment',
        description: 'Create a new payment',
        inputSchema: {
          type: 'object',
          properties: {
            payment: { type: 'object' }
          },
          required: ['payment']
        }
      },

      // BILLS (same as invoices with Type=ACCPAY)
      {
        name: 'xero_list_bills',
        description: 'List all bills (payable invoices)',
        inputSchema: {
          type: 'object',
          properties: {
            page: { type: 'number' },
            pageSize: { type: 'number' },
            where: { type: 'string' },
            order: { type: 'string' }
          }
        }
      },
      {
        name: 'xero_create_bill',
        description: 'Create a new bill',
        inputSchema: {
          type: 'object',
          properties: {
            bill: { type: 'object', description: 'Bill data (Contact, LineItems, Type=ACCPAY)' }
          },
          required: ['bill']
        }
      },

      // CREDIT NOTES
      {
        name: 'xero_list_credit_notes',
        description: 'List all credit notes',
        inputSchema: {
          type: 'object',
          properties: {
            page: { type: 'number' },
            pageSize: { type: 'number' },
            where: { type: 'string' }
          }
        }
      },
      {
        name: 'xero_create_credit_note',
        description: 'Create a new credit note',
        inputSchema: {
          type: 'object',
          properties: {
            creditNote: { type: 'object' }
          },
          required: ['creditNote']
        }
      },

      // PURCHASE ORDERS
      {
        name: 'xero_list_purchase_orders',
        description: 'List all purchase orders',
        inputSchema: {
          type: 'object',
          properties: {
            page: { type: 'number' },
            pageSize: { type: 'number' },
            where: { type: 'string' }
          }
        }
      },
      {
        name: 'xero_create_purchase_order',
        description: 'Create a new purchase order',
        inputSchema: {
          type: 'object',
          properties: {
            purchaseOrder: { type: 'object' }
          },
          required: ['purchaseOrder']
        }
      },

      // QUOTES
      {
        name: 'xero_list_quotes',
        description: 'List all quotes',
        inputSchema: {
          type: 'object',
          properties: {
            page: { type: 'number' },
            pageSize: { type: 'number' },
            where: { type: 'string' }
          }
        }
      },
      {
        name: 'xero_create_quote',
        description: 'Create a new quote',
        inputSchema: {
          type: 'object',
          properties: {
            quote: { type: 'object' }
          },
          required: ['quote']
        }
      },

      // REPORTS
      {
        name: 'xero_get_balance_sheet',
        description: 'Get balance sheet report',
        inputSchema: {
          type: 'object',
          properties: {
            date: { type: 'string', description: 'Report date (YYYY-MM-DD)' },
            periods: { type: 'number', description: 'Number of periods to compare' }
          }
        }
      },
      {
        name: 'xero_get_profit_and_loss',
        description: 'Get profit and loss report',
        inputSchema: {
          type: 'object',
          properties: {
            fromDate: { type: 'string', description: 'Start date (YYYY-MM-DD)' },
            toDate: { type: 'string', description: 'End date (YYYY-MM-DD)' }
          }
        }
      },
      {
        name: 'xero_get_trial_balance',
        description: 'Get trial balance report',
        inputSchema: {
          type: 'object',
          properties: {
            date: { type: 'string', description: 'Report date (YYYY-MM-DD)' }
          }
        }
      },
      {
        name: 'xero_get_bank_summary',
        description: 'Get bank summary report',
        inputSchema: {
          type: 'object',
          properties: {
            fromDate: { type: 'string' },
            toDate: { type: 'string' }
          }
        }
      },

      // EMPLOYEES
      {
        name: 'xero_list_employees',
        description: 'List all employees (basic accounting)',
        inputSchema: {
          type: 'object',
          properties: {
            where: { type: 'string' }
          }
        }
      },

      // TAX RATES
      {
        name: 'xero_list_tax_rates',
        description: 'List all tax rates',
        inputSchema: {
          type: 'object',
          properties: {
            where: { type: 'string' }
          }
        }
      },

      // ITEMS
      {
        name: 'xero_list_items',
        description: 'List all inventory/service items',
        inputSchema: {
          type: 'object',
          properties: {
            where: { type: 'string' }
          }
        }
      },
      {
        name: 'xero_create_item',
        description: 'Create a new inventory/service item',
        inputSchema: {
          type: 'object',
          properties: {
            item: { type: 'object' }
          },
          required: ['item']
        }
      },

      // ORGANISATION
      {
        name: 'xero_get_organisation',
        description: 'Get organisation details',
        inputSchema: {
          type: 'object',
          properties: {}
        }
      },

      // TRACKING CATEGORIES
      {
        name: 'xero_list_tracking_categories',
        description: 'List all tracking categories',
        inputSchema: {
          type: 'object',
          properties: {}
        }
      }
    ];

    return this.toolsCache;
  }

  private async handleToolCall(name: string, args: Record<string, unknown>): Promise<unknown> {
    switch (name) {
      // INVOICES
      case 'xero_list_invoices':
        return this.client.getInvoices(args);
      case 'xero_get_invoice':
        return this.client.getInvoice(args.invoiceId as any);
      case 'xero_create_invoice':
        return this.client.createInvoice(args.invoice as any);
      case 'xero_update_invoice':
        return this.client.updateInvoice(args.invoiceId as any, args.invoice as any);

      // CONTACTS
      case 'xero_list_contacts':
        return this.client.getContacts(args);
      case 'xero_get_contact':
        return this.client.getContact(args.contactId as any);
      case 'xero_create_contact':
        return this.client.createContact(args.contact as any);
      case 'xero_update_contact':
        return this.client.updateContact(args.contactId as any, args.contact as any);

      // ACCOUNTS
      case 'xero_list_accounts':
        return this.client.getAccounts(args);
      case 'xero_get_account':
        return this.client.getAccount(args.accountId as any);
      case 'xero_create_account':
        return this.client.createAccount(args.account as any);

      // BANK TRANSACTIONS
      case 'xero_list_bank_transactions':
        return this.client.getBankTransactions(args);
      case 'xero_get_bank_transaction':
        return this.client.getBankTransaction(args.bankTransactionId as any);
      case 'xero_create_bank_transaction':
        return this.client.createBankTransaction(args.transaction as any);

      // PAYMENTS
      case 'xero_list_payments':
        return this.client.getPayments(args);
      case 'xero_create_payment':
        return this.client.createPayment(args.payment as any);

      // BILLS
      case 'xero_list_bills':
        return this.client.getInvoices({ ...args, where: 'Type=="ACCPAY"' });
      case 'xero_create_bill':
        return this.client.createInvoice({ ...(args.bill as any), Type: 'ACCPAY' });

      // CREDIT NOTES
      case 'xero_list_credit_notes':
        return this.client.getCreditNotes(args);
      case 'xero_create_credit_note':
        return this.client.createCreditNote(args.creditNote as any);

      // PURCHASE ORDERS
      case 'xero_list_purchase_orders':
        return this.client.getPurchaseOrders(args);
      case 'xero_create_purchase_order':
        return this.client.createPurchaseOrder(args.purchaseOrder as any);

      // QUOTES
      case 'xero_list_quotes':
        return this.client.getQuotes(args);
      case 'xero_create_quote':
        return this.client.createQuote(args.quote as any);

      // REPORTS
      case 'xero_get_balance_sheet':
        return this.client.getBalanceSheet(args.date as string, args.periods as number);
      case 'xero_get_profit_and_loss':
        return this.client.getProfitAndLoss(args.fromDate as string, args.toDate as string);
      case 'xero_get_trial_balance':
        return this.client.getTrialBalance(args.date as string);
      case 'xero_get_bank_summary':
        return this.client.getBankSummary(args.fromDate as string, args.toDate as string);

      // EMPLOYEES
      case 'xero_list_employees':
        return this.client.getEmployees(args);

      // TAX RATES
      case 'xero_list_tax_rates':
        return this.client.getTaxRates(args);

      // ITEMS
      case 'xero_list_items':
        return this.client.getItems(args);
      case 'xero_create_item':
        return this.client.createItem(args.item as any);

      // ORGANISATION
      case 'xero_get_organisation':
        return this.client.getOrganisations();

      // TRACKING CATEGORIES
      case 'xero_list_tracking_categories':
        return this.client.getTrackingCategories(args);

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

  async run(): Promise<void> {
    const transport = new StdioServerTransport();
    await this.server.connect(transport);
    console.error('Xero MCP Server running on stdio');
  }
}
