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

export type CustomerInvoiceCreationAttributes = InferCreationAttributes<
  CustomerInvoiceModel,
  { omit: "items" }
> & {
  // creo que no es necesario
  //items: CustomerInvoiceItemCreationAttributes[];
  //customer_id: string;
};

export class CustomerInvoiceModel extends Model<
  InferAttributes<CustomerInvoiceModel, { omit: "items" }>,
  InferCreationAttributes<CustomerInvoiceModel, { omit: "items" }>
> {
  // To avoid table creation
  /*static async sync(): Promise<any> {
      return Promise.resolve();
    }*/

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

    CustomerInvoiceModel.hasMany(CustomerInvoiceItemModel, {
      as: "items",
      foreignKey: "customer_invoice_id",
      onDelete: "CASCADE",
    });
  }

  declare id: string;
  declare status: string;

  declare issue_date: string;
  declare invoice_number: string;
  declare invoice_type: string;
  declare invoice_customer_reference?: CreationOptional<string>;

  declare lang_code: string;
  declare currency_code: string;

  declare customer_id: string;
  declare customer_tin: string;
  declare customer_name: string;

  declare customer_street: string;
  declare customer_street2?: CreationOptional<string>;
  declare customer_city: string;
  declare customer_state: string;
  declare customer_postal_code: string;
  declare customer_country: string;

  declare subtotal_price?: CreationOptional<number>;

  declare discount?: CreationOptional<number>;
  declare discount_price?: CreationOptional<number>;

  declare before_tax_price?: CreationOptional<number>;

  declare tax?: CreationOptional<number>;
  declare tax_price?: CreationOptional<number>;

  declare total_price?: CreationOptional<number>;

  declare notes?: CreationOptional<string>;

  declare items: NonAttribute<CustomerInvoiceItemModel[]>;

  declare integrity_hash?: CreationOptional<string>;
  declare previous_invoice_id?: CreationOptional<string>;
  declare signed_at?: CreationOptional<string>;
}

export default (sequelize: Sequelize) => {
  CustomerInvoiceModel.init(
    {
      id: {
        type: DataTypes.UUID,
        primaryKey: true,
      },

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

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

      invoice_number: {
        type: DataTypes.STRING(),
        allowNull: false,
      },

      invoice_customer_reference: {
        type: new DataTypes.STRING(),
      },

      invoice_type: {
        type: new DataTypes.STRING(),
        allowNull: false,
      },

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

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

      customer_id: {
        type: new DataTypes.UUID(),
        allowNull: false,
      },

      customer_name: {
        type: DataTypes.STRING,
        allowNull: false,
      },

      customer_tin: {
        type: DataTypes.STRING,
        allowNull: false,
      },

      customer_street: {
        type: DataTypes.STRING,
        allowNull: false,
      },

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

      customer_city: {
        type: DataTypes.STRING,
        allowNull: false,
      },
      customer_state: {
        type: DataTypes.STRING,
        allowNull: false,
      },
      customer_postal_code: {
        type: DataTypes.STRING,
        allowNull: false,
      },
      customer_country: {
        type: DataTypes.STRING,
        allowNull: false,
      },

      subtotal_price: {
        type: new DataTypes.BIGINT(),
        allowNull: true,
        defaultValue: null,
      },

      discount: {
        type: new DataTypes.SMALLINT(),
        allowNull: true,
        defaultValue: null,
      },

      discount_price: {
        type: new DataTypes.BIGINT(),
        allowNull: true,
        defaultValue: null,
      },

      before_tax_price: {
        type: new DataTypes.BIGINT(),
        allowNull: true,
        defaultValue: null,
      },

      tax: {
        type: new DataTypes.SMALLINT(),
        allowNull: true,
        defaultValue: null,
      },

      tax_price: {
        type: new DataTypes.BIGINT(),
        allowNull: true,
        defaultValue: null,
      },

      total_price: {
        type: new DataTypes.BIGINT(),
        allowNull: true,
        defaultValue: null,
      },

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

      integrity_hash: {
        type: DataTypes.STRING,
        allowNull: true,
        defaultValue: null,
        comment: "Hash criptográfico para asegurar integridad",
      },
      previous_invoice_id: {
        type: DataTypes.UUID,
        allowNull: true,
        defaultValue: null,
        comment: "Referencia a la factura anterior (si aplica)",
      },
      signed_at: {
        type: DataTypes.DATE,
        allowNull: true,
        defaultValue: null,
        comment: "Fecha en que la factura fue firmada digitalmente",
      },
    },
    {
      sequelize,
      tableName: "customer_invoices",

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

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

      indexes: [
        { name: "status_idx", fields: ["status"] },
        { name: "invoice_number_idx", fields: ["invoice_number"] },
        { name: "deleted_at_idx", fields: ["deleted_at"] },
        { name: "signed_at_idx", fields: ["signed_at"] },
      ],

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

      defaultScope: {},

      scopes: {},
    }
  );
  return CustomerInvoiceModel;
};
