import {
  CreationOptional,
  DataTypes,
  InferAttributes,
  InferCreationAttributes,
  Model,
  NonAttribute,
  Sequelize,
} from "sequelize";
import {
  CustomerInvoiceItemCreationAttributes,
  CustomerInvoiceItemModel,
} from "./customer-invoice-item.model";

import { CustomerModel } from "@erp/customers/api";
import {
  CustomerInvoiceTaxCreationAttributes,
  CustomerInvoiceTaxModel,
} from "./customer-invoice-tax.model";

export type CustomerInvoiceCreationAttributes = InferCreationAttributes<
  CustomerInvoiceModel,
  { omit: "items" | "taxes" | "current_customer" }
> & {
  items?: CustomerInvoiceItemCreationAttributes[];
  taxes?: CustomerInvoiceTaxCreationAttributes[];
};

export class CustomerInvoiceModel extends Model<
  InferAttributes<CustomerInvoiceModel>,
  InferCreationAttributes<CustomerInvoiceModel, { omit: "items" | "taxes" }>
> {
  // Version
  // declare version: CreationOptional<number>;

  declare id: string;
  declare company_id: string;

  declare is_proforma: boolean;
  declare status: string;
  declare series: CreationOptional<string | null>;
  declare invoice_number: CreationOptional<string | null>;
  declare invoice_date: CreationOptional<string>;
  declare operation_date: CreationOptional<string | null>;
  declare language_code: CreationOptional<string>;
  declare currency_code: CreationOptional<string>;

  declare reference: CreationOptional<string | null>;
  declare description: CreationOptional<string | null>;

  declare notes: CreationOptional<string | null>;

  // Método de pago
  declare payment_method_id: CreationOptional<string | null>;
  declare payment_method_description: CreationOptional<string | null>;

  // Subtotal
  declare subtotal_amount_value: number;
  declare subtotal_amount_scale: number;

  // Discount percentage
  declare discount_percentage_value: number;
  declare discount_percentage_scale: number;

  // Discount amount
  declare discount_amount_value: number;
  declare discount_amount_scale: number;

  // Taxable amount (base imponible)
  declare taxable_amount_value: number;
  declare taxable_amount_scale: number;

  // Total taxes amount / taxes total
  declare taxes_amount_value: number;
  declare taxes_amount_scale: number;

  // Total
  declare total_amount_value: number;
  declare total_amount_scale: number;

  // Customer
  declare customer_id: string;
  declare customer_tin: CreationOptional<string | null>;
  declare customer_name: CreationOptional<string | null>;
  declare customer_street: CreationOptional<string | null>;
  declare customer_street2: CreationOptional<string | null>;
  declare customer_city: CreationOptional<string | null>;
  declare customer_province: CreationOptional<string | null>;
  declare customer_postal_code: CreationOptional<string | null>;
  declare customer_country: CreationOptional<string | null>;

  // Relaciones
  declare items: NonAttribute<CustomerInvoiceItemModel[]>;
  declare taxes: NonAttribute<CustomerInvoiceTaxModel[]>;
  declare current_customer: NonAttribute<CustomerModel>;

  static associate(database: Sequelize) {
    const {
      CustomerInvoiceModel,
      CustomerInvoiceItemModel,
      CustomerModel,
      CustomerInvoiceTaxModel,
      VerifactuRecordModel,
    } = database.models;

    CustomerInvoiceModel.belongsTo(CustomerModel, {
      as: "current_customer",
      foreignKey: "customer_id",
      constraints: false,
    });

    CustomerInvoiceModel.hasMany(CustomerInvoiceItemModel, {
      as: "items",
      foreignKey: "invoice_id",
      sourceKey: "id",
      constraints: true,
      onDelete: "CASCADE",
      onUpdate: "CASCADE",
    });

    CustomerInvoiceModel.hasMany(CustomerInvoiceTaxModel, {
      as: "taxes",
      foreignKey: "invoice_id",
      sourceKey: "id",
      constraints: true,
      onDelete: "CASCADE",
      onUpdate: "CASCADE",
    });
  }

  static hooks(database: Sequelize) {}
}

export default (database: Sequelize) => {
  CustomerInvoiceModel.init(
    {
      /*version: {
        type: DataTypes.INTEGER.UNSIGNED,
        allowNull: false,
        defaultValue: 0,
      },*/

      id: {
        type: DataTypes.UUID,
        primaryKey: true,
      },

      company_id: {
        type: DataTypes.UUID,
        allowNull: false,
      },

      is_proforma: {
        type: DataTypes.BOOLEAN,
        allowNull: false,
        defaultValue: true,
      },

      status: {
        type: new DataTypes.STRING(),
        allowNull: false,
        defaultValue: "draft",
      },

      series: {
        type: new DataTypes.STRING(),
        allowNull: true,
        defaultValue: null,
      },

      invoice_number: {
        type: new DataTypes.STRING(),
        allowNull: true,
        defaultValue: null,
      },

      invoice_date: {
        type: new DataTypes.DATEONLY(),
        allowNull: false,
      },

      operation_date: {
        type: new DataTypes.DATEONLY(),
        allowNull: true,
        defaultValue: null,
      },

      language_code: {
        type: DataTypes.STRING(2),
        allowNull: false,
        defaultValue: "es",
      },

      currency_code: {
        type: new DataTypes.STRING(3),
        allowNull: false,
        defaultValue: "EUR",
      },

      reference: {
        type: new DataTypes.STRING(),
        allowNull: true,
        defaultValue: null,
      },

      description: {
        type: new DataTypes.STRING(),
        allowNull: true,
        defaultValue: null,
      },

      notes: {
        type: new DataTypes.TEXT(),
        allowNull: true,
        defaultValue: null,
      },

      payment_method_id: {
        type: DataTypes.UUID,
        allowNull: true,
        defaultValue: null,
      },

      payment_method_description: {
        type: new DataTypes.STRING(),
        allowNull: true,
        defaultValue: null,
      },

      subtotal_amount_value: {
        type: new DataTypes.BIGINT(), // importante: evita problemas de precisión con valores grandes
        allowNull: false,
        defaultValue: 0,
      },

      subtotal_amount_scale: {
        type: new DataTypes.SMALLINT(),
        allowNull: false,
        defaultValue: 2,
      },

      discount_percentage_value: {
        type: new DataTypes.SMALLINT(),
        allowNull: false,
        defaultValue: 0,
      },

      discount_percentage_scale: {
        type: new DataTypes.SMALLINT(),
        allowNull: false,
        defaultValue: 2,
      },

      discount_amount_value: {
        type: new DataTypes.BIGINT(),
        allowNull: false,
        defaultValue: 0,
      },

      discount_amount_scale: {
        type: new DataTypes.SMALLINT(),
        allowNull: false,
        defaultValue: 2,
      },

      taxable_amount_value: {
        type: new DataTypes.BIGINT(), // importante: evita problemas de precisión con valores grandes
        allowNull: false,
        defaultValue: 0,
      },
      taxable_amount_scale: {
        type: new DataTypes.SMALLINT(),
        allowNull: false,
        defaultValue: 2,
      },

      taxes_amount_value: {
        type: new DataTypes.BIGINT(), // importante: evita problemas de precisión con valores grandes
        allowNull: false,
        defaultValue: 0,
      },
      taxes_amount_scale: {
        type: new DataTypes.SMALLINT(),
        allowNull: false,
        defaultValue: 2,
      },

      total_amount_value: {
        type: new DataTypes.BIGINT(), // importante: evita problemas de precisión con valores grandes
        allowNull: false,
        defaultValue: 0,
      },

      total_amount_scale: {
        type: new DataTypes.SMALLINT(),
        allowNull: false,
        defaultValue: 2,
      },

      customer_id: {
        type: DataTypes.UUID,
        allowNull: false,
      },

      customer_tin: {
        type: DataTypes.STRING,
        allowNull: true,
        defaultValue: null,
      },

      customer_name: {
        type: DataTypes.STRING,
        allowNull: true,
        defaultValue: null,
      },

      customer_street: {
        type: DataTypes.STRING,
        allowNull: true,
        defaultValue: null,
      },

      customer_street2: {
        type: DataTypes.STRING,
        allowNull: true,
        defaultValue: null,
      },

      customer_city: {
        type: DataTypes.STRING,
        allowNull: true,
        defaultValue: null,
      },

      customer_province: {
        type: DataTypes.STRING,
        allowNull: true,
        defaultValue: null,
      },

      customer_postal_code: {
        type: DataTypes.STRING,
        allowNull: true,
        defaultValue: null,
      },

      customer_country: {
        type: DataTypes.STRING,
        allowNull: true,
        defaultValue: null,
      },
    },
    {
      sequelize: database,
      tableName: "customer_invoices",

      underscored: true,
      paranoid: true, // softs deletes
      timestamps: true,

      createdAt: "created_at",
      updatedAt: "updated_at",
      deletedAt: "deleted_at",

      indexes: [{ name: "company_idx", fields: ["company_id"], unique: false }],

      whereMergeStrategy: "and", // <- cómo tratar el merge de un scope

      defaultScope: {},

      scopes: {},

      /*hooks: {
        // Incrementa la versión en cada update exitoso (OCC).
        beforeUpdate: (instance) => {
          const current = instance.get("version") as number;
          instance.set("version", current + 1);
        },
      },*/
    }
  );

  return CustomerInvoiceModel;
};
