/**
 * Xero Contact Tools
 * Handles contacts, customers, suppliers, and contact groups
 */

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

const AddressSchema = z.object({
  AddressType: z.enum(['POBOX', 'STREET', 'DELIVERY']).optional(),
  AddressLine1: z.string().optional(),
  AddressLine2: z.string().optional(),
  AddressLine3: z.string().optional(),
  AddressLine4: z.string().optional(),
  City: z.string().optional(),
  Region: z.string().optional(),
  PostalCode: z.string().optional(),
  Country: z.string().optional(),
  AttentionTo: z.string().optional()
});

const PhoneSchema = z.object({
  PhoneType: z.enum(['DEFAULT', 'DDI', 'MOBILE', 'FAX']).optional(),
  PhoneNumber: z.string(),
  PhoneAreaCode: z.string().optional(),
  PhoneCountryCode: z.string().optional()
});

export function getTools(_client: XeroClient): Tool[] {
  return [
    // List contacts
    {
      name: 'xero_list_contacts',
      description: 'List all contacts (customers, suppliers). Use where clause for filtering (e.g., IsCustomer==true or IsSupplier==true).',
      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., IsCustomer==true)' },
          order: { type: 'string', description: 'Order by field (e.g., Name ASC)' },
          includeArchived: { type: 'boolean', description: 'Include archived contacts' },
          ifModifiedSince: { type: 'string', description: 'ISO date to get only records modified since' }
        }
      }
    },

    // Get single contact
    {
      name: 'xero_get_contact',
      description: 'Get a specific contact by ID. Returns full contact details including addresses, phones, and balances.',
      inputSchema: {
        type: 'object',
        properties: {
          contactId: { type: 'string', description: 'Contact ID (GUID)' }
        },
        required: ['contactId']
      }
    },

    // Create contact
    {
      name: 'xero_create_contact',
      description: 'Create a new contact (customer or supplier). Name is required. Can optionally set addresses, phones, and tax settings.',
      inputSchema: {
        type: 'object',
        properties: {
          name: { type: 'string', description: 'Contact name (required)' },
          firstName: { type: 'string', description: 'First name (for person contacts)' },
          lastName: { type: 'string', description: 'Last name (for person contacts)' },
          emailAddress: { type: 'string', description: 'Email address' },
          contactNumber: { type: 'string', description: 'Contact number (internal reference)' },
          accountNumber: { type: 'string', description: 'Account number' },
          taxNumber: { type: 'string', description: 'Tax/VAT number' },
          isCustomer: { type: 'boolean', description: 'Mark as customer' },
          isSupplier: { type: 'boolean', description: 'Mark as supplier' },
          defaultCurrency: { type: 'string', description: 'Default currency code (e.g., USD)' },
          addresses: {
            type: 'array',
            items: {
              type: 'object',
              properties: {
                AddressType: { type: 'string', enum: ['POBOX', 'STREET', 'DELIVERY'] },
                AddressLine1: { type: 'string' },
                AddressLine2: { type: 'string' },
                City: { type: 'string' },
                Region: { type: 'string' },
                PostalCode: { type: 'string' },
                Country: { type: 'string' }
              }
            }
          },
          phones: {
            type: 'array',
            items: {
              type: 'object',
              properties: {
                PhoneType: { type: 'string', enum: ['DEFAULT', 'DDI', 'MOBILE', 'FAX'] },
                PhoneNumber: { type: 'string' },
                PhoneAreaCode: { type: 'string' },
                PhoneCountryCode: { type: 'string' }
              },
              required: ['PhoneNumber']
            }
          }
        },
        required: ['name']
      }
    },

    // Update contact
    {
      name: 'xero_update_contact',
      description: 'Update an existing contact. Can update any field including addresses and phones.',
      inputSchema: {
        type: 'object',
        properties: {
          contactId: { type: 'string', description: 'Contact ID (GUID)' },
          name: { type: 'string', description: 'Contact name' },
          emailAddress: { type: 'string', description: 'Email address' },
          contactNumber: { type: 'string', description: 'Contact number' },
          accountNumber: { type: 'string', description: 'Account number' },
          taxNumber: { type: 'string', description: 'Tax/VAT number' },
          isCustomer: { type: 'boolean', description: 'Mark as customer' },
          isSupplier: { type: 'boolean', description: 'Mark as supplier' },
          addresses: {
            type: 'array',
            items: {
              type: 'object',
              properties: {
                AddressType: { type: 'string' },
                AddressLine1: { type: 'string' },
                City: { type: 'string' },
                PostalCode: { type: 'string' }
              }
            }
          }
        },
        required: ['contactId']
      }
    },

    // Archive contact
    {
      name: 'xero_archive_contact',
      description: 'Archive a contact. Archived contacts are hidden from most views but can be restored.',
      inputSchema: {
        type: 'object',
        properties: {
          contactId: { type: 'string', description: 'Contact ID (GUID)' }
        },
        required: ['contactId']
      }
    },

    // List contact groups
    {
      name: 'xero_list_contact_groups',
      description: 'List all contact groups. Contact groups are used to organize contacts.',
      inputSchema: {
        type: 'object',
        properties: {
          where: { type: 'string', description: 'Filter expression' },
          order: { type: 'string', description: 'Order by field' }
        }
      }
    },

    // Create contact group
    {
      name: 'xero_create_contact_group',
      description: 'Create a new contact group for organizing contacts.',
      inputSchema: {
        type: 'object',
        properties: {
          name: { type: 'string', description: 'Contact group name' }
        },
        required: ['name']
      }
    },

    // Add contact to group
    {
      name: 'xero_add_contact_to_group',
      description: 'Add a contact to a contact group.',
      inputSchema: {
        type: 'object',
        properties: {
          contactGroupId: { type: 'string', description: 'Contact group ID (GUID)' },
          contactId: { type: 'string', description: 'Contact ID (GUID)' }
        },
        required: ['contactGroupId', 'contactId']
      }
    }
  ];
}

export async function handleContactTool(
  toolName: string,
  args: Record<string, unknown>,
  client: XeroClient
): Promise<unknown> {
  switch (toolName) {
    case 'xero_list_contacts': {
      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.getContacts(options);
    }

    case 'xero_get_contact': {
      const { contactId } = z.object({ contactId: z.string() }).parse(args);
      return await client.getContact(contactId as any);
    }

    case 'xero_create_contact': {
      const schema = z.object({
        name: z.string(),
        firstName: z.string().optional(),
        lastName: z.string().optional(),
        emailAddress: z.string().optional(),
        contactNumber: z.string().optional(),
        accountNumber: z.string().optional(),
        taxNumber: z.string().optional(),
        isCustomer: z.boolean().optional(),
        isSupplier: z.boolean().optional(),
        defaultCurrency: z.string().optional(),
        addresses: z.array(AddressSchema).optional(),
        phones: z.array(PhoneSchema).optional()
      });
      const data = schema.parse(args);
      
      const contact: any = {
        Name: data.name
      };
      
      if (data.firstName) contact.FirstName = data.firstName;
      if (data.lastName) contact.LastName = data.lastName;
      if (data.emailAddress) contact.EmailAddress = data.emailAddress;
      if (data.contactNumber) contact.ContactNumber = data.contactNumber;
      if (data.accountNumber) contact.AccountNumber = data.accountNumber;
      if (data.taxNumber) contact.TaxNumber = data.taxNumber;
      if (data.isCustomer !== undefined) contact.IsCustomer = data.isCustomer;
      if (data.isSupplier !== undefined) contact.IsSupplier = data.isSupplier;
      if (data.defaultCurrency) contact.DefaultCurrency = data.defaultCurrency;
      if (data.addresses) contact.Addresses = data.addresses;
      if (data.phones) contact.Phones = data.phones;
      
      return await client.createContact(contact);
    }

    case 'xero_update_contact': {
      const schema = z.object({
        contactId: z.string(),
        name: z.string().optional(),
        emailAddress: z.string().optional(),
        contactNumber: z.string().optional(),
        accountNumber: z.string().optional(),
        taxNumber: z.string().optional(),
        isCustomer: z.boolean().optional(),
        isSupplier: z.boolean().optional(),
        addresses: z.array(AddressSchema).optional()
      });
      const data = schema.parse(args);
      
      const updates: any = {};
      if (data.name) updates.Name = data.name;
      if (data.emailAddress) updates.EmailAddress = data.emailAddress;
      if (data.contactNumber) updates.ContactNumber = data.contactNumber;
      if (data.accountNumber) updates.AccountNumber = data.accountNumber;
      if (data.taxNumber) updates.TaxNumber = data.taxNumber;
      if (data.isCustomer !== undefined) updates.IsCustomer = data.isCustomer;
      if (data.isSupplier !== undefined) updates.IsSupplier = data.isSupplier;
      if (data.addresses) updates.Addresses = data.addresses;
      
      return await client.updateContact(data.contactId as any, updates);
    }

    case 'xero_archive_contact': {
      const { contactId } = z.object({ contactId: z.string() }).parse(args);
      return await client.updateContact(contactId as any, { ContactStatus: 'ARCHIVED' as any });
    }

    case 'xero_list_contact_groups': {
      const options = {
        where: args.where as string | undefined,
        order: args.order as string | undefined
      };
      return await client.getContactGroups(options);
    }

    case 'xero_create_contact_group': {
      const { name } = z.object({ name: z.string() }).parse(args);
      return await client.createContactGroup({ Name: name });
    }

    case 'xero_add_contact_to_group': {
      const { contactGroupId, contactId } = z.object({
        contactGroupId: z.string(),
        contactId: z.string()
      }).parse(args);
      
      // To add a contact to a group, we need to get the contact first, then update the group
      const contact = await client.getContact(contactId as any);
      return await client.createContactGroup({
        Name: '', // Not used when updating existing group
        ContactGroupID: contactGroupId as any,
        Contacts: [contact]
      });
    }

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