import { createAction, Property, OAuth2PropertyValue } from '@activepieces/pieces-framework';
import { bexioAuth } from '../auth';
import { BexioClient } from '../common/client';
import { bexioCommonProps } from '../common/props';

export const createSalesInvoiceAction = createAction({
  auth: bexioAuth,
  name: 'create_sales_invoice',
  displayName: 'Create Sales Invoice',
  description: 'Create a new product-based sales invoice',
  audience: 'both',
  aiMetadata: { description: 'Creates a new sales invoice in Bexio from one or more line-item positions (custom, article, text, subtotal, discount, or page-break). Use when billing a customer for products or services; requires a user, language, bank account, currency, payment type, tax handling, and at least one position. Not idempotent: each call creates a separate invoice, so guard against duplicates.', idempotent: false },
  props: {
    document_nr: Property.ShortText({
      displayName: 'Document Number',
      description: 'Invoice number (required if automatic numbering is disabled)',
      required: false,
    }),
    title: Property.ShortText({
      displayName: 'Title',
      description: 'Invoice title',
      required: false,
    }),
    contact_id: Property.Dropdown({
      auth: bexioAuth,
      displayName: 'Contact',
      description: 'The contact for this invoice',
      required: false,
      refreshers: [],
      options: async ({ auth }) => {
        if (!auth) {
          return {
            disabled: true,
            placeholder: 'Connect your Bexio account first',
            options: [],
          };
        }
        try {
          const client = new BexioClient(auth);
          const contacts = await client.get<Array<{
            id: number;
            contact_type_id: number;
            name_1: string;
            name_2?: string | null;
            nr?: string | null;
          }>>('/2.0/contact');

          return {
            disabled: false,
            options: contacts.map((contact) => {
              const name = contact.name_2
                ? `${contact.name_2} ${contact.name_1}`
                : contact.name_1;
              const label = contact.nr ? `${name} (#${contact.nr})` : name;
              return {
                label,
                value: contact.id,
              };
            }),
          };
        } catch (error) {
          return {
            disabled: true,
            placeholder: 'Failed to load contacts',
            options: [],
          };
        }
      },
    }),
    contact_sub_id: Property.Dropdown({
      auth: bexioAuth,
      displayName: 'Contact Sub',
      description: 'Contact sub-address (optional)',
      required: false,
      refreshers: [],
      options: async ({ auth }) => {
        if (!auth) {
          return {
            disabled: true,
            placeholder: 'Connect your Bexio account first',
            options: [],
          };
        }

        try {
          const client = new BexioClient(auth);
          const contacts = await client.get<Array<{
            id: number;
            contact_type_id: number;
            name_1: string;
            name_2?: string | null;
            nr?: string | null;
          }>>('/2.0/contact');

          return {
            disabled: false,
            options: contacts.map((contact) => {
              const name = contact.name_2
                ? `${contact.name_2} ${contact.name_1}`
                : contact.name_1;
              const label = contact.nr ? `${name} (#${contact.nr})` : name;
              return {
                label,
                value: contact.id,
              };
            }),
          };
        } catch (error) {
          return {
            disabled: true,
            placeholder: 'Failed to load contacts',
            options: [],
          };
        }
      },
    }),
    user_id: Property.Dropdown({
      auth: bexioAuth,
      displayName: 'User',
      description: 'User assigned to this invoice',
      required: true,
      refreshers: [],
      options: async ({ auth }) => {
        if (!auth) {
          return {
            disabled: true,
            placeholder: 'Connect your Bexio account first',
            options: [],
          };
        }

        try {
          const client = new BexioClient(auth);
          const users = await client.get<Array<{ id: number; firstname: string | null; lastname: string | null; email: string }>>('/3.0/users');

          return {
            disabled: false,
            options: users.map((user) => ({
              label: `${user.firstname || ''} ${user.lastname || ''}`.trim() || user.email,
              value: user.id,
            })),
          };
        } catch (error) {
          return {
            disabled: true,
            placeholder: 'Failed to load users',
            options: [],
          };
        }
      },
    }),
    pr_project_id: Property.Dropdown({
      auth: bexioAuth,
      displayName: 'Project',
      description: 'Project associated with this invoice',
      required: false,
      refreshers: [],
      options: async ({ auth }) => {
        if (!auth) {
          return {
            disabled: true,
            placeholder: 'Connect your Bexio account first',
            options: [],
          };
        }

        try {
          const client = new BexioClient(auth);
          const projects = await client.get<Array<{
            id: number;
            name: string;
            nr?: string;
          }>>('/2.0/pr_project');

          return {
            disabled: false,
            options: projects.map((project) => ({
              label: project.nr ? `${project.name} (#${project.nr})` : project.name,
              value: project.id,
            })),
          };
        } catch (error) {
          return {
            disabled: true,
            placeholder: 'Failed to load projects',
            options: [],
          };
        }
      },
    }),
    language_id: Property.Dropdown({
      auth: bexioAuth,
      displayName: 'Language',
      description: 'Language for the invoice',
      required: true,
      refreshers: [],
      options: async ({ auth }) => {
        if (!auth) {
          return {
            disabled: true,
            placeholder: 'Connect your Bexio account first',
            options: [],
          };
        }

        try {
          const client = new BexioClient(auth);
          const languages = await client.get<Array<{ id: number; name: string }>>('/2.0/language');

          return {
            disabled: false,
            options: languages.map((lang) => ({
              label: lang.name,
              value: lang.id,
            })),
          };
        } catch (error) {
          return {
            disabled: true,
            placeholder: 'Failed to load languages',
            options: [],
          };
        }
      },
    }),
    bank_account_id: Property.Dropdown({
      auth: bexioAuth,
      displayName: 'Bank Account',
      description: 'Bank account for payment',
      required: true,
      refreshers: [],
      options: async ({ auth }) => {
        if (!auth) {
          return {
            disabled: true,
            placeholder: 'Connect your Bexio account first',
            options: [],
          };
        }

        try {
          const client = new BexioClient(auth);
          const bankAccounts = await client.get<Array<{
            id: number;
            name: string;
            iban_nr?: string;
            bank_account_nr?: string;
          }>>('/3.0/banking/accounts');

          return {
            disabled: false,
            options: bankAccounts.map((account) => {
              const iban = account.iban_nr || account.bank_account_nr;
              return {
                label: iban ? `${account.name} (${iban})` : account.name,
                value: account.id,
              };
            }),
          };
        } catch (error) {
          return {
            disabled: true,
            placeholder: 'Failed to load bank accounts',
            options: [],
          };
        }
      },
    }),
    currency_id: bexioCommonProps.currency({
      displayName: 'Currency',
      required: true,
    }),
    payment_type_id: Property.Dropdown({
      auth: bexioAuth,
      displayName: 'Payment Type',
      description: 'Payment type for this invoice',
      required: true,
      refreshers: [],
      options: async ({ auth }) => {
        if (!auth) {
          return {
            disabled: true,
            placeholder: 'Connect your Bexio account first',
            options: [],
          };
        }

        try {
          const client = new BexioClient(auth);
          const paymentTypes = await client.get<Array<{ id: number; name: string }>>('/2.0/payment_type');

          return {
            disabled: false,
            options: paymentTypes.map((type) => ({
              label: type.name,
              value: type.id,
            })),
          };
        } catch (error) {
          return {
            disabled: true,
            placeholder: 'Failed to load payment types',
            options: [],
          };
        }
      },
    }),
    header: Property.LongText({
      displayName: 'Header',
      description: 'Header text for the invoice',
      required: false,
    }),
    footer: Property.LongText({
      displayName: 'Footer',
      description: 'Footer text for the invoice',
      required: false,
    }),
    mwst_type: Property.StaticDropdown({
      displayName: 'Tax Type',
      description: 'How taxes are handled',
      required: true,
      defaultValue: 0,
      options: {
        disabled: false,
        options: [
          { label: 'Including taxes', value: 0 },
          { label: 'Excluding taxes', value: 1 },
          { label: 'Exempt from taxes', value: 2 },
        ],
      },
    }),
    mwst_is_net: Property.Checkbox({
      displayName: 'Tax is Net',
      description: 'If taxes are included, set to true to add taxes to total, false to include in total',
      required: false,
      defaultValue: false,
    }),
    show_position_taxes: Property.Checkbox({
      displayName: 'Show Position Taxes',
      description: 'Show taxes for each position',
      required: false,
      defaultValue: false,
    }),
    is_valid_from: Property.ShortText({
      displayName: 'Valid From',
      description: 'Invoice valid from date (YYYY-MM-DD)',
      required: false,
    }),
    is_valid_to: Property.ShortText({
      displayName: 'Valid To',
      description: 'Invoice valid to date (YYYY-MM-DD)',
      required: false,
    }),
    contact_address_manual: Property.LongText({
      displayName: 'Manual Contact Address',
      description: 'Override contact address (leave empty to use contact address)',
      required: false,
    }),
    reference: Property.ShortText({
      displayName: 'Reference',
      description: 'Reference number',
      required: false,
    }),
    api_reference: Property.ShortText({
      displayName: 'API Reference',
      description: 'Reference for API use (can only be edited via API)',
      required: false,
    }),
    template_slug: Property.Dropdown({
      auth: bexioAuth,
      displayName: 'Document Template',
      description: 'Document template for the invoice',
      required: false,
      refreshers: [],
      options: async ({ auth }) => {
        if (!auth) {
          return {
            disabled: true,
            placeholder: 'Connect your Bexio account first',
            options: [],
          };
        }

        try {
          const client = new BexioClient(auth);
          const templates = await client.get<Array<{
            template_slug: string;
            name: string;
            is_default: boolean;
            default_for_document_types: string[];
          }>>('/3.0/document_templates');

          return {
            disabled: false,
            options: templates.map((template) => ({
              label: template.is_default ? `${template.name} (Default)` : template.name,
              value: template.template_slug,
            })),
          };
        } catch (error) {
          return {
            disabled: true,
            placeholder: 'Failed to load templates',
            options: [],
          };
        }
      },
    }),
    positionFields: Property.DynamicProperties({  
      auth: bexioAuth,
      displayName: 'Invoice Positions',
      description: 'Configure invoice line items',
      required: true,
      refreshers: ['auth'],
      props: async ({ auth }) => {
        let units: Array<{ id: number; name: string }> = [];
        let accounts: Array<{ id: number; account_no: string; name: string }> = [];
        let taxes: Array<{ id: number; name: string; percentage: string }> = [];

        if (auth) {
            try {
                const client = new BexioClient(auth);
              units = await client.get<Array<{ id: number; name: string }>>('/2.0/unit').catch(() => []);
              accounts = await client.get<Array<{ id: number; account_no: string; name: string }>>('/accounts').catch(() => []);
              const taxesResponse = await client.get<Array<{
                id: number;
                name: string;
                value: number;
                display_name?: string;
              }>>('/3.0/taxes?types=sales_tax&scope=active').catch(() => []);
              taxes = taxesResponse.map((tax) => ({
                id: tax.id,
                name: tax.display_name || tax.name,
                percentage: tax.value.toString(),
              }));
            } catch (error) {
              // Ignore error, use empty array as fallback
            }
        }

        const unitOptions = units.map((unit) => ({ label: unit.name, value: unit.id }));
        const accountOptions = accounts.map((acc) => ({ label: `${acc.account_no} - ${acc.name}`, value: acc.id }));
        const taxOptions = taxes.map((tax) => ({ label: `${tax.name} (${tax.percentage}%)`, value: tax.id }));

        return {
          positions: Property.Array({
            displayName: 'Positions',
            description: 'Invoice line items',
            required: true,
            properties: {
              type: Property.StaticDropdown({
                displayName: 'Position Type',
                description: 'Type of invoice position',
                required: true,
                defaultValue: 'KbPositionCustom',
                options: {
                  disabled: false,
                  options: [
                    { label: 'Custom Position', value: 'KbPositionCustom' },
                    { label: 'Article Position', value: 'KbPositionArticle' },
                    { label: 'Text Position', value: 'KbPositionText' },
                    { label: 'Subtotal Position', value: 'KbPositionSubtotal' },
                    { label: 'Page Break Position', value: 'KbPositionPagebreak' },
                    { label: 'Discount Position', value: 'KbPositionDiscount' },
                  ],
                },
              }),
              amount: Property.ShortText({
                displayName: 'Amount',
                description: 'Quantity/amount',
                required: true,
              }),
              unit_id: unitOptions.length > 0
                ? Property.StaticDropdown({
                    displayName: 'Unit',
                    description: 'Unit of measurement',
                    required: false,
                    options: {
                      disabled: false,
                      options: unitOptions,
                    },
                  })
                : Property.Number({
                    displayName: 'Unit ID',
                    description: 'Unit ID (use List Units action to find IDs)',
                    required: false,
                  }),
              account_id: accountOptions.length > 0
                ? Property.StaticDropdown({
                    displayName: 'Account',
                    description: 'Account for this position',
                    required: false,
                    options: {
                      disabled: false,
                      options: accountOptions,
                    },
                  })
                : Property.Number({
                    displayName: 'Account ID',
                    description: 'Account ID (use List Accounts action to find IDs)',
                    required: false,
                  }),
              tax_id: taxOptions.length > 0
                ? Property.StaticDropdown({
                    displayName: 'Tax',
                    description: 'Tax rate (only active sales taxes)',
                    required: false,
                    options: {
                      disabled: false,
                      options: taxOptions,
                    },
                  })
                : Property.Number({
                    displayName: 'Tax ID',
                    description: 'Tax ID (use List Taxes action to find IDs)',
                    required: false,
                  }),
              text: Property.LongText({
                displayName: 'Description',
                description: 'Position description/text',
                required: false,
              }),
              unit_price: Property.ShortText({
                displayName: 'Unit Price',
                description: 'Price per unit (max 6 decimals)',
                required: false,
              }),
              discount_in_percent: Property.ShortText({
                displayName: 'Discount (%)',
                description: 'Discount percentage (max 6 decimals)',
                required: false,
              }),
              parent_id: Property.Number({
                displayName: 'Parent ID',
                description: 'Parent position ID (for grouped positions)',
                required: false,
              }),
            },
          }),
        };
      },
    }),
  },
  async run(context) {
    const client = new BexioClient(context.auth);
    const props = context.propsValue;

    const requestBody: Record<string, unknown> = {};

    if (props['user_id']) {
      requestBody['user_id'] = props['user_id'];
    }
    if (props['language_id']) {
      requestBody['language_id'] = props['language_id'];
    }
    if (props['bank_account_id']) {
      requestBody['bank_account_id'] = props['bank_account_id'];
    }
    if (props['currency_id']) {
      requestBody['currency_id'] = props['currency_id'];
    }
    if (props['payment_type_id']) {
      requestBody['payment_type_id'] = props['payment_type_id'];
    }

    if (props['document_nr']) {
      requestBody['document_nr'] = props['document_nr'];
    }
    if (props['title'] !== undefined) {
      requestBody['title'] = props['title'] || null;
    }
    if (props['contact_id']) {
      requestBody['contact_id'] = props['contact_id'];
    }
    if (props['contact_sub_id']) {
      requestBody['contact_sub_id'] = props['contact_sub_id'];
    }
    if (props['pr_project_id']) {
      requestBody['pr_project_id'] = props['pr_project_id'];
    }
    if (props['header']) {
      requestBody['header'] = props['header'];
    }
    if (props['footer']) {
      requestBody['footer'] = props['footer'];
    }
    if (props['mwst_type'] !== undefined) {
      requestBody['mwst_type'] = props['mwst_type'];
    }
    if (props['mwst_is_net'] !== undefined) {
      requestBody['mwst_is_net'] = props['mwst_is_net'];
    }
    if (props['show_position_taxes'] !== undefined) {
      requestBody['show_position_taxes'] = props['show_position_taxes'];
    }
    if (props['is_valid_from']) {
      requestBody['is_valid_from'] = props['is_valid_from'];
    }
    if (props['is_valid_to']) {
      requestBody['is_valid_to'] = props['is_valid_to'];
    }
    if (props['contact_address_manual']) {
      requestBody['contact_address_manual'] = props['contact_address_manual'];
    }
    if (props['reference']) {
      requestBody['reference'] = props['reference'];
    }
    if (props['api_reference']) {
      requestBody['api_reference'] = props['api_reference'];
    }
    if (props['template_slug']) {
      requestBody['template_slug'] = props['template_slug'];
    }

    const positionFields = props['positionFields'] as Record<string, unknown>;
    if (positionFields && positionFields['positions'] && Array.isArray(positionFields['positions'])) {
      requestBody['positions'] = (positionFields['positions'] as Array<Record<string, unknown>>).map((position) => {
        const pos: Record<string, unknown> = {
          type: position['type'] || 'KbPositionCustom',
        };

        if (position['amount']) {
          pos['amount'] = position['amount'];
        }
        if (position['unit_id']) {
          pos['unit_id'] = position['unit_id'];
        }
        if (position['account_id']) {
          pos['account_id'] = position['account_id'];
        }
        if (position['tax_id']) {
          pos['tax_id'] = position['tax_id'];
        }
        if (position['text']) {
          pos['text'] = position['text'];
        }
        if (position['unit_price']) {
          pos['unit_price'] = position['unit_price'];
        }
        if (position['discount_in_percent']) {
          pos['discount_in_percent'] = position['discount_in_percent'];
        }
        if (position['parent_id']) {
          pos['parent_id'] = position['parent_id'];
        }

        return pos;
      });
    }

    const response = await client.post('/2.0/kb_invoice', requestBody);

    return response;
  },
});

