import * as Sequelize from "sequelize";
import { DataTypes, Model } from "sequelize";

export default class p2pOffer
  extends Model<p2pOfferAttributes, p2pOfferCreationAttributes>
  implements p2pOfferAttributes
{
  public id!: string;
  public userId!: string;
  public type!: "BUY" | "SELL";
  public currency!: string;
  public walletType!: "FIAT" | "SPOT" | "ECO";
  public priceCurrency?: string; // Currency used for pricing (USD, EUR, GBP, etc.)
  public amountConfig!: {
    total: number;
    min?: number;
    max?: number;
    availableBalance?: number;
  };
  public priceConfig!: {
    model: "FIXED" | "MARGIN";
    value: number;
    marketPrice?: number;
    finalPrice: number;
    currency?: string; // Currency for the price (USD, EUR, GBP, etc.)
    marginType?: "percentage" | "fixed";
  };
  public tradeSettings!: {
    autoCancel: number;
    kycRequired: boolean;
    visibility: "PUBLIC" | "PRIVATE";
    termsOfTrade?: string;
    additionalNotes?: string;
  };
  public locationSettings?: {
    country?: string;
    region?: string;
    city?: string;
    restrictions?: string[];
  };
  public userRequirements?: {
    minCompletedTrades?: number;
    minSuccessRate?: number;
    minAccountAge?: number;
    trustedOnly?: boolean;
  };
  public status!:
    | "DRAFT"
    | "PENDING_APPROVAL"
    | "ACTIVE"
    | "PAUSED"
    | "COMPLETED"
    | "CANCELLED"
    | "REJECTED"
    | "EXPIRED";
  public views!: number;
  public systemTags?: string[];
  public adminNotes?: string;
  public activityLog?: Array<{
    type: string;
    adminId?: string;
    adminName?: string;
    previousStatus?: string;
    reason?: string;
    createdAt: string;
  }>;
  public readonly createdAt!: Date;
  public readonly updatedAt!: Date;
  public readonly deletedAt!: Date;

  public static initModel(sequelize: Sequelize.Sequelize): typeof p2pOffer {
    return p2pOffer.init(
      {
        id: {
          type: DataTypes.UUID,
          defaultValue: DataTypes.UUIDV4,
          primaryKey: true,
          allowNull: false,
        },
        userId: {
          type: DataTypes.UUID,
          allowNull: false,
          validate: { isUUID: { args: 4, msg: "userId must be a valid UUID" } },
        },
        type: {
          type: DataTypes.ENUM("BUY", "SELL"),
          allowNull: false,
          validate: {
            isIn: { args: [["BUY", "SELL"]], msg: "Invalid trade type" },
          },
        },
        currency: {
          type: DataTypes.STRING(50),
          allowNull: false,
          validate: { notEmpty: { msg: "currency must not be empty" } },
        },
        walletType: {
          type: DataTypes.ENUM("FIAT", "SPOT", "ECO"),
          allowNull: false,
          validate: {
            isIn: {
              args: [["FIAT", "SPOT", "ECO"]],
              msg: "Invalid wallet type",
            },
          },
        },
        priceCurrency: {
          type: DataTypes.STRING(10),
          allowNull: true,
          comment: "Currency used for pricing (USD, EUR, GBP, etc.)",
        },
        amountConfig: {
          type: DataTypes.JSON,
          allowNull: false,
          get() {
            const value = this.getDataValue('amountConfig');
            if (typeof value === 'string') {
              try {
                return JSON.parse(value);
              } catch (e) {
                return {};
              }
            }
            return value || {};
          },
          set(value: any) {
            if (typeof value === 'string') {
              try {
                JSON.parse(value); // Validate it's valid JSON
                this.setDataValue('amountConfig', value as any);
              } catch (e) {
                this.setDataValue('amountConfig', JSON.stringify({}) as any);
              }
            } else if (typeof value === 'object' && value !== null) {
              this.setDataValue('amountConfig', JSON.stringify(value) as any);
            } else {
              this.setDataValue('amountConfig', JSON.stringify({}) as any);
            }
          }
        },
        priceConfig: {
          type: DataTypes.JSON,
          allowNull: false,
          get() {
            const value = this.getDataValue('priceConfig');
            if (typeof value === 'string') {
              try {
                return JSON.parse(value);
              } catch (e) {
                return {};
              }
            }
            return value || {};
          },
          set(value: any) {
            if (typeof value === 'string') {
              try {
                JSON.parse(value); // Validate it's valid JSON
                this.setDataValue('priceConfig', value as any);
              } catch (e) {
                this.setDataValue('priceConfig', JSON.stringify({}) as any);
              }
            } else if (typeof value === 'object' && value !== null) {
              this.setDataValue('priceConfig', JSON.stringify(value) as any);
            } else {
              this.setDataValue('priceConfig', JSON.stringify({}) as any);
            }
          }
        },
        tradeSettings: {
          type: DataTypes.JSON,
          allowNull: false,
          get() {
            const value = this.getDataValue('tradeSettings');
            if (typeof value === 'string') {
              try {
                return JSON.parse(value);
              } catch (e) {
                return {};
              }
            }
            return value || {};
          },
          set(value: any) {
            if (typeof value === 'string') {
              try {
                JSON.parse(value); // Validate it's valid JSON
                this.setDataValue('tradeSettings', value as any);
              } catch (e) {
                this.setDataValue('tradeSettings', JSON.stringify({}) as any);
              }
            } else if (typeof value === 'object' && value !== null) {
              this.setDataValue('tradeSettings', JSON.stringify(value) as any);
            } else {
              this.setDataValue('tradeSettings', JSON.stringify({}) as any);
            }
          }
        },
        locationSettings: {
          type: DataTypes.JSON,
          allowNull: true,
          get() {
            const value = this.getDataValue('locationSettings');
            if (value === null) return null;
            if (typeof value === 'string') {
              try {
                return JSON.parse(value);
              } catch (e) {
                return null;
              }
            }
            return value;
          },
          set(value: any) {
            if (value === null || value === undefined) {
              this.setDataValue('locationSettings', null as any);
            } else if (typeof value === 'string') {
              try {
                JSON.parse(value); // Validate it's valid JSON
                this.setDataValue('locationSettings', value as any);
              } catch (e) {
                this.setDataValue('locationSettings', null as any);
              }
            } else if (typeof value === 'object') {
              this.setDataValue('locationSettings', JSON.stringify(value) as any);
            } else {
              this.setDataValue('locationSettings', null as any);
            }
          }
        },
        userRequirements: {
          type: DataTypes.JSON,
          allowNull: true,
          get() {
            const value = this.getDataValue('userRequirements');
            if (value === null) return null;
            if (typeof value === 'string') {
              try {
                return JSON.parse(value);
              } catch (e) {
                return null;
              }
            }
            return value;
          },
          set(value: any) {
            if (value === null || value === undefined) {
              this.setDataValue('userRequirements', null as any);
            } else if (typeof value === 'string') {
              try {
                JSON.parse(value); // Validate it's valid JSON
                this.setDataValue('userRequirements', value as any);
              } catch (e) {
                this.setDataValue('userRequirements', null as any);
              }
            } else if (typeof value === 'object') {
              this.setDataValue('userRequirements', JSON.stringify(value) as any);
            } else {
              this.setDataValue('userRequirements', null as any);
            }
          }
        },
        status: {
          type: DataTypes.ENUM(
            "DRAFT",
            "PENDING_APPROVAL",
            "ACTIVE",
            "PAUSED",
            "COMPLETED",
            "CANCELLED",
            "REJECTED",
            "EXPIRED"
          ),
          allowNull: false,
          defaultValue: "DRAFT",
        },
        views: {
          type: DataTypes.INTEGER,
          allowNull: false,
          defaultValue: 0,
        },
        systemTags: {
          type: DataTypes.JSON,
          allowNull: true,
        },
        adminNotes: {
          type: DataTypes.TEXT,
          allowNull: true,
        },
        activityLog: {
          type: DataTypes.JSON,
          allowNull: true,
          defaultValue: [],
        },
      },
      {
        sequelize,
        modelName: "p2pOffer",
        tableName: "p2p_offers",
        timestamps: true,
        paranoid: true,
      }
    );
  }

  public static associate(models: any) {
    p2pOffer.belongsTo(models.user, {
      as: "user",
      foreignKey: "userId",
      onDelete: "CASCADE",
      onUpdate: "CASCADE",
    });
    p2pOffer.belongsToMany(models.p2pPaymentMethod, {
      through: "p2p_offer_payment_method",
      as: "paymentMethods",
      foreignKey: "offerId",
      otherKey: "paymentMethodId",
      onDelete: "CASCADE",
      onUpdate: "CASCADE",
    });
    p2pOffer.hasOne(models.p2pOfferFlag, {
      as: "flag",
      foreignKey: "offerId",
      onDelete: "CASCADE",
      onUpdate: "CASCADE",
    });
    p2pOffer.hasMany(models.p2pTrade, {
      as: "trades",
      foreignKey: "offerId",
      onDelete: "CASCADE",
      onUpdate: "CASCADE",
    });
  }
}
