import { ClassError, ObjectBase } from '@tomei/general';
import {
  CutOffStatus,
  ActivationTrigger,
  SourceFeedName,
} from '../../enum/feed.enum';
import { IPriceFeedCutOffHistoryAttr } from '../../interfaces/price-feed-cut-off-history-attr.interface';
import { FeedCutOffHistoryRepository } from './feed-cut-off-history.repository';
import { Op } from 'sequelize';

export class FeedCutOffHistory
  extends ObjectBase
  implements IPriceFeedCutOffHistoryAttr
{
  ObjectId: string;
  ObjectName: string;
  ObjectType = FeedCutOffHistory.name;
  TableName: string;
  FeedName: SourceFeedName;
  Status: CutOffStatus;
  ActivationDateTime: Date;
  ActivationTrigger: ActivationTrigger;
  ActivatedById: string;
  DeactivationDateTime: Date;
  DeactivatedById: string;

  private static _Repo = new FeedCutOffHistoryRepository();

  get FeedCutOffHistoryId(): string {
    return this.ObjectId;
  }

  set FeedCutOffHistoryId(value: string) {
    this.ObjectId = value;
  }

  private constructor(feedCutOffHistory?: IPriceFeedCutOffHistoryAttr) {
    super();
    if (feedCutOffHistory) {
      this.ObjectId = feedCutOffHistory.FeedCutOffHistoryId;
      this.FeedName = feedCutOffHistory.FeedName;
      this.Status = feedCutOffHistory.Status;
      this.ActivationDateTime = feedCutOffHistory.ActivationDateTime;
      this.ActivationTrigger = feedCutOffHistory.ActivationTrigger;
      this.ActivatedById = feedCutOffHistory.ActivatedById;
      this.DeactivationDateTime = feedCutOffHistory.DeactivationDateTime;
      this.DeactivatedById = feedCutOffHistory.DeactivatedById;
    }
  }

  static async init(
    feedCutOffHistoryId?: string,
    dbTransaction?: any,
  ): Promise<FeedCutOffHistory> {
    try {
      if (feedCutOffHistoryId) {
        const data = await this._Repo.findByPk(feedCutOffHistoryId, {
          transaction: dbTransaction,
        });

        if (data) {
          return new FeedCutOffHistory(data);
        } else {
          throw new ClassError(
            'FeedCutOffHistory',
            'FeedCutOffHistoryErrMsg01',
            'FeedCutOffHistory not found',
            'init',
          );
        }
      }
      return new FeedCutOffHistory();
    } catch (error) {
      throw error;
    }
  }

  async create(
    dbTransaction?: any,
    activatedById?: string,
  ): Promise<FeedCutOffHistory> {
    try {
      //Make sure all required fields are set
      if (!this.FeedName || !this.ActivationTrigger) {
        throw new ClassError(
          'FeedCutOffHistory',
          'FeedCutOffHistoryErrMsg02',
          'Missing required fields',
          'create',
        );
      }

      //Set the id, status, and activation date time
      this.ObjectId = this.createId();
      this.Status = CutOffStatus.ACTIVE;
      this.ActivationDateTime = new Date();
      //If activatedByIdExist set it to ActivatedById
      if (activatedById) {
        this.ActivatedById = activatedById;
      }

      //Save the record to the database
      await FeedCutOffHistory._Repo.create(
        {
          FeedCutOffHistoryId: this.ObjectId,
          FeedName: this.FeedName,
          Status: this.Status,
          ActivationDateTime: this.ActivationDateTime,
          ActivationTrigger: this.ActivationTrigger,
          ActivatedById: this.ActivatedById,
          DeactivationDateTime: this.DeactivationDateTime,
          DeactivatedById: this.DeactivatedById,
        },
        {
          transaction: dbTransaction,
        },
      );

      //Return the object
      return this;
    } catch (error) {
      throw error;
    }
  }

  public static async deactivate(
    feedName: string,
    deactivatedById: string,
    dbTransaction?: any,
  ): Promise<FeedCutOffHistory> {
    try {
      //Retrieve the latest record from the database
      const data = await FeedCutOffHistory._Repo.findAll({
        order: [['ActivationDateTime', 'DESC']],
        transaction: dbTransaction,
        where: {
          FeedName: feedName,
          Status: CutOffStatus.ACTIVE,
        },
      });

      //If no record is found, throw an error
      if (!data) {
        throw new ClassError(
          'FeedCutOffHistory',
          'FeedCutOffHistoryErrMsg03',
          'FeedCutOffHistory not found',
          'deactivate',
        );
      }

      for (const item of data) {
        item.DeactivationDateTime = new Date();
        item.DeactivatedById = deactivatedById;
        item.Status = CutOffStatus.DEACTIVATED;
        //Save the record to the database
        await item.save({
          transaction: dbTransaction,
        });
      }

      //Return the object
      return new FeedCutOffHistory(data[0]);
    } catch (error) {
      throw error;
    }
  }

  public static async findAll(
    page: number,
    row: number,
    search?: {
      ActivationDateTime?: {
        startDate: Date;
        endDate: Date;
      };
      DeactivationDateTime?: {
        startDate: Date;
        endDate: Date;
      };
      ActivationTrigger?: ActivationTrigger;
      FeedName?: string;
    },
    dbTransaction?: any,
  ): Promise<{
    rows: IPriceFeedCutOffHistoryAttr[];
    count: number;
  }> {
    try {
      const queryObj: any = {};

      const options: any = {
        transaction: dbTransaction,
        limit: row,
        offset: row * (page - 1),
        order: [['ActivationDateTime', 'DESC']],
      };

      if (search) {
        if (search.ActivationDateTime) {
          queryObj.ActivationDateTime = {
            [Op.between]: [
              search.ActivationDateTime.startDate,
              search.ActivationDateTime.endDate,
            ],
          };
        }

        if (search.DeactivationDateTime) {
          queryObj.DeactivationDateTime = {
            [Op.between]: [
              search.DeactivationDateTime.startDate,
              search.DeactivationDateTime.endDate,
            ],
          };
        }

        if (search.ActivationTrigger) {
          queryObj.ActivationTrigger = search.ActivationTrigger;
        }

        if (search.FeedName) {
          queryObj.FeedName = {
            [Op.like]: `%${search.FeedName}%`,
          };
        }
      }

      return await FeedCutOffHistory._Repo.findAllWithPagination({
        where: queryObj,
        ...options,
      });
    } catch (error) {
      throw error;
    }
  }
}
