import { ClassError } from '@tomei/general';
import { ApplicationLog } from '@tomei/log';
import { IFeedAttr } from '../../interfaces/price-feed-attr.interface';
import { FeedRepository } from './feed.repository';
import { NonSourceFeedName, SourceFeedName } from '../../enum/feed.enum';
import { FeedManualPriceHistory } from '../feed-manual-price-history/feed-manual-price-history';
import { FeedHistory } from '../feed-history/feed-history';
import { TomeiPriceHistory } from '../tomei-price/tomei-price';
import { CompanyFeedAccess } from '../company-feed-access/company-feed-access';

export class Feed implements IFeedAttr {
  FeedName: SourceFeedName | NonSourceFeedName;
  IsSourcePriceYN: string;
  IsManualPriceActivatedYN: string;
  CurrentManualPriceHistoryId: string;
  Weight: number;

  protected static _Repo = new FeedRepository();
  protected static logger = new ApplicationLog('live-price', 'Feed');

  constructor(feedAttr?: IFeedAttr) {
    if (feedAttr) {
      this.FeedName = feedAttr.FeedName;
      this.IsSourcePriceYN = feedAttr.IsSourcePriceYN;
      this.IsManualPriceActivatedYN = feedAttr.IsManualPriceActivatedYN;
      this.CurrentManualPriceHistoryId = feedAttr.CurrentManualPriceHistoryId;
      this.Weight = feedAttr.Weight;
    }
  }

  public static async init(dbTransaction: any, FeedName?: string) {
    try {
      if (FeedName) {
        const feed = await Feed._Repo.findByPk(FeedName, dbTransaction);
        if (feed) {
          return new Feed(feed);
        } else {
          const error = new ClassError(
            'Feed',
            'FeedErrMsg00',
            'Feed Not Found',
          );
          throw error;
        }
      }
      return new Feed();
    } catch (error) {
      const classError = new ClassError('Feed', 'FeedErrMsg01', error.message);
      await Feed.logger.error({
        error,
        methodName: 'init',
        transaction: dbTransaction,
      });
      throw classError;
    }
  }

  public async save(dbTransaction: any) {
    try {
      const feed = await Feed._Repo.findOne({
        where: {
          FeedName: this.FeedName,
        },
        transaction: dbTransaction,
      });
      const payload: IFeedAttr = {
        FeedName: this.FeedName,
        IsSourcePriceYN: this.IsSourcePriceYN,
        IsManualPriceActivatedYN: this.IsManualPriceActivatedYN,
        CurrentManualPriceHistoryId: this.CurrentManualPriceHistoryId,
        Weight: this.Weight,
      };
      if (feed) {
        await Feed._Repo.update(payload, {
          where: {
            FeedName: this.FeedName,
          },
          transaction: dbTransaction,
        });
      } else {
        await Feed._Repo.create(payload, { transaction: dbTransaction });
      }
    } catch (error) {
      const classError = new ClassError('Feed', 'FeedErrMsg02', error.message);
      await Feed.logger.error({
        error,
        methodName: 'save',
        transaction: dbTransaction,
      });
      throw classError;
    }
  }

  public async setManualPrice(
    activatedById: string,
    buyPrice: number,
    sellPrice: number,
    dbTransaction: any,
    companyCode?: string,
  ) {
    try {
      //Instantiate a new feed manual price history
      let feedManualPriceHistory = await FeedManualPriceHistory.init();
      feedManualPriceHistory.FeedName = this.FeedName;
      feedManualPriceHistory.ActivatedById = activatedById;
      //Call FeedManualPriceHistory.create to create a new manual price history record
      feedManualPriceHistory = await feedManualPriceHistory.create(
        this.FeedName,
        activatedById,
        buyPrice,
        sellPrice,
        companyCode,
        dbTransaction,
      );
      //Update the manual price history id
      this.CurrentManualPriceHistoryId =
        feedManualPriceHistory.FeedManualPriceHistoryId;
      //Update the manual price status
      this.IsManualPriceActivatedYN = 'Y';
      //Update the feed record in the database
      await this.save(dbTransaction);
    } catch (error) {
      await Feed.logger.error({
        error,
        methodName: 'setManualPrice',
        transaction: dbTransaction,
      });
      throw error;
    }
  }

  public async deactivateManualPrice(
    dbTransaction: any,
    deactivatedById: string,
    companyCode?: string, // Make companyCode optional
  ) {
    try {
      //Call FeedManualPriceHistory.deactivate to deactivate the manual price
      await FeedManualPriceHistory.deactivate(
        this.FeedName,
        deactivatedById,
        companyCode, // Pass companyCode (can be undefined for source feeds)
        dbTransaction,
      );
      //Update the manual price status
      this.IsManualPriceActivatedYN = 'N';
      //Update the feed record in the database
      await this.save(dbTransaction);
    } catch (error) {
      await Feed.logger.error({
        error,
        methodName: 'deactivateManualPrice',
        transaction: dbTransaction,
      });
      throw error;
    }
  }

  public async createTomeiPriceHistory(
    feedHistory: FeedHistory,
    dbTransaction: any,
    companyCode: string = 'CTH',
  ) {
    try {
      // Get accessible feeds for this company from the database
      const accessibleFeeds = await CompanyFeedAccess.getAccessibleFeeds(
        dbTransaction,
        companyCode,
      );

      // Filter feeds that are relevant to this source feed
      const relevantFeeds = accessibleFeeds.filter((feedName) => {
        if (this.FeedName === SourceFeedName.XAUMYR) {
          return feedName.includes('GOLD');
        } else if (this.FeedName === SourceFeedName.XAGMYR) {
          return feedName.includes('SILVER');
        }
        return false;
      });

      if (relevantFeeds && relevantFeeds.length > 0) {
        for (const nonSourceFeed of relevantFeeds) {
          const tomeiPriceHistory = await TomeiPriceHistory.init();
          await tomeiPriceHistory.saveTomeiPrice(
            nonSourceFeed,
            feedHistory,
            undefined,
            undefined,
            undefined,
            companyCode,
            dbTransaction,
          );
        }
      }
    } catch (error) {
      await Feed.logger.error({
        error,
        methodName: 'createTomeiPriceHistory',
        transaction: dbTransaction,
      });
      throw error;
    }
  }
}
