const db = require('../models');
const FileDBApi = require('./file');
const crypto = require('crypto');
const Utils = require('../utils');

const Sequelize = db.Sequelize;
const Op = Sequelize.Op;

module.exports = class Brand_rate_cardsDBApi {
  static async create(data, options) {
    const currentUser = (options && options.currentUser) || { id: null };
    const transaction = (options && options.transaction) || undefined;

    const brand_rate_cards = await db.brand_rate_cards.create(
      {
        id: data.id || undefined,

        name: data.name || null,
        rate_card_type: data.rate_card_type || null,
        status: data.status || null,
        currency: data.currency || null,
        push_new_values: data.push_new_values || false,

        inherit_default_rate_card: data.inherit_default_rate_card || false,

        service_count: data.service_count || null,
        discipline: data.discipline || null,
        output_channel: data.output_channel || null,
        staff_skills: data.staff_skills || null,
        rate_card_owner: data.rate_card_owner || null,
        rate_card_id: data.rate_card_id || null,
        markets: data.markets || null,
        languages: data.languages || null,
        valid_from: data.valid_from || null,
        valid_to: data.valid_to || null,
        version_number: data.version_number || null,
        commercial_owner: data.commercial_owner || null,
        review_date: data.review_date || null,
        assumptions: data.assumptions || null,
        no_fixed_text: data.no_fixed_text || null,
        yes_fixed_text: data.yes_fixed_text || null,
        importHash: data.importHash || null,
        createdById: currentUser.id,
        updatedById: currentUser.id,
      },
      { transaction },
    );

    await brand_rate_cards.setClient(data.client || null, {
      transaction,
    });

    await brand_rate_cards.setBrand(data.brand || null, {
      transaction,
    });

    return brand_rate_cards;
  }

  static async bulkImport(data, options) {
    const currentUser = (options && options.currentUser) || { id: null };
    const transaction = (options && options.transaction) || undefined;

    // Prepare data - wrapping individual data transformations in a map() method
    const brand_rate_cardsData = data.map((item, index) => ({
      id: item.id || undefined,

      name: item.name || null,
      rate_card_type: item.rate_card_type || null,
      status: item.status || null,
      currency: item.currency || null,
      push_new_values: item.push_new_values || false,

      inherit_default_rate_card: item.inherit_default_rate_card || false,

      service_count: item.service_count || null,
      discipline: item.discipline || null,
      output_channel: item.output_channel || null,
      staff_skills: item.staff_skills || null,
      rate_card_owner: item.rate_card_owner || null,
      rate_card_id: item.rate_card_id || null,
      markets: item.markets || null,
      languages: item.languages || null,
      valid_from: item.valid_from || null,
      valid_to: item.valid_to || null,
      version_number: item.version_number || null,
      commercial_owner: item.commercial_owner || null,
      review_date: item.review_date || null,
      assumptions: item.assumptions || null,
      no_fixed_text: item.no_fixed_text || null,
      yes_fixed_text: item.yes_fixed_text || null,
      importHash: item.importHash || null,
      createdById: currentUser.id,
      updatedById: currentUser.id,
      createdAt: new Date(Date.now() + index * 1000),
    }));

    // Bulk create items
    const brand_rate_cards = await db.brand_rate_cards.bulkCreate(
      brand_rate_cardsData,
      { transaction },
    );

    // For each item created, replace relation files

    return brand_rate_cards;
  }

  static async update(id, data, options) {
    const currentUser = (options && options.currentUser) || { id: null };
    const transaction = (options && options.transaction) || undefined;

    const brand_rate_cards = await db.brand_rate_cards.findByPk(
      id,
      {},
      { transaction },
    );

    const updatePayload = {};

    if (data.name !== undefined) updatePayload.name = data.name;

    if (data.rate_card_type !== undefined)
      updatePayload.rate_card_type = data.rate_card_type;

    if (data.status !== undefined) updatePayload.status = data.status;

    if (data.currency !== undefined) updatePayload.currency = data.currency;

    if (data.push_new_values !== undefined)
      updatePayload.push_new_values = data.push_new_values;

    if (data.inherit_default_rate_card !== undefined)
      updatePayload.inherit_default_rate_card = data.inherit_default_rate_card;

    if (data.service_count !== undefined)
      updatePayload.service_count = data.service_count;

    if (data.discipline !== undefined)
      updatePayload.discipline = data.discipline;

    if (data.output_channel !== undefined)
      updatePayload.output_channel = data.output_channel;

    if (data.staff_skills !== undefined)
      updatePayload.staff_skills = data.staff_skills;

    if (data.rate_card_owner !== undefined)
      updatePayload.rate_card_owner = data.rate_card_owner;

    if (data.rate_card_id !== undefined)
      updatePayload.rate_card_id = data.rate_card_id;

    if (data.markets !== undefined) updatePayload.markets = data.markets;

    if (data.languages !== undefined) updatePayload.languages = data.languages;

    if (data.valid_from !== undefined)
      updatePayload.valid_from = data.valid_from;

    if (data.valid_to !== undefined) updatePayload.valid_to = data.valid_to;

    if (data.version_number !== undefined)
      updatePayload.version_number = data.version_number;

    if (data.commercial_owner !== undefined)
      updatePayload.commercial_owner = data.commercial_owner;

    if (data.review_date !== undefined)
      updatePayload.review_date = data.review_date;

    if (data.assumptions !== undefined)
      updatePayload.assumptions = data.assumptions;

    if (data.no_fixed_text !== undefined)
      updatePayload.no_fixed_text = data.no_fixed_text;

    if (data.yes_fixed_text !== undefined)
      updatePayload.yes_fixed_text = data.yes_fixed_text;

    updatePayload.updatedById = currentUser.id;

    await brand_rate_cards.update(updatePayload, { transaction });

    if (data.client !== undefined) {
      await brand_rate_cards.setClient(
        data.client,

        { transaction },
      );
    }

    if (data.brand !== undefined) {
      await brand_rate_cards.setBrand(
        data.brand,

        { transaction },
      );
    }

    return brand_rate_cards;
  }

  static async deleteByIds(ids, options) {
    const currentUser = (options && options.currentUser) || { id: null };
    const transaction = (options && options.transaction) || undefined;

    const brand_rate_cards = await db.brand_rate_cards.findAll({
      where: {
        id: {
          [Op.in]: ids,
        },
      },
      transaction,
    });

    await db.sequelize.transaction(async (transaction) => {
      for (const record of brand_rate_cards) {
        await record.update({ deletedBy: currentUser.id }, { transaction });
      }
      for (const record of brand_rate_cards) {
        await record.destroy({ transaction });
      }
    });

    return brand_rate_cards;
  }

  static async remove(id, options) {
    const currentUser = (options && options.currentUser) || { id: null };
    const transaction = (options && options.transaction) || undefined;

    const brand_rate_cards = await db.brand_rate_cards.findByPk(id, options);

    await brand_rate_cards.update(
      {
        deletedBy: currentUser.id,
      },
      {
        transaction,
      },
    );

    await brand_rate_cards.destroy({
      transaction,
    });

    return brand_rate_cards;
  }

  static async findBy(where, options) {
    const transaction = (options && options.transaction) || undefined;

    const brand_rate_cards = await db.brand_rate_cards.findOne(
      { where },
      { transaction },
    );

    if (!brand_rate_cards) {
      return brand_rate_cards;
    }

    const output = brand_rate_cards.get({ plain: true });

    output.brands_link_rate_card =
      await brand_rate_cards.getBrands_link_rate_card({
        transaction,
      });

    output.client = await brand_rate_cards.getClient({
      transaction,
    });

    output.brand = await brand_rate_cards.getBrand({
      transaction,
    });

    return output;
  }

  static async findAll(filter, options) {
    const limit = filter.limit || 0;
    let offset = 0;
    let where = {};
    const currentPage = +filter.page;

    offset = currentPage * limit;

    const orderBy = null;

    const transaction = (options && options.transaction) || undefined;

    let include = [
      {
        model: db.clients,
        as: 'client',

        where: filter.client
          ? {
              [Op.or]: [
                {
                  id: {
                    [Op.in]: filter.client
                      .split('|')
                      .map((term) => Utils.uuid(term)),
                  },
                },
                {
                  id: {
                    [Op.or]: filter.client
                      .split('|')
                      .map((term) => ({ [Op.iLike]: `%${term}%` })),
                  },
                },
              ],
            }
          : {},
      },

      {
        model: db.brands,
        as: 'brand',

        where: filter.brand
          ? {
              [Op.or]: [
                {
                  id: {
                    [Op.in]: filter.brand
                      .split('|')
                      .map((term) => Utils.uuid(term)),
                  },
                },
                {
                  id: {
                    [Op.or]: filter.brand
                      .split('|')
                      .map((term) => ({ [Op.iLike]: `%${term}%` })),
                  },
                },
              ],
            }
          : {},
      },
    ];

    if (filter) {
      if (filter.id) {
        where = {
          ...where,
          ['id']: Utils.uuid(filter.id),
        };
      }

      if (filter.name) {
        where = {
          ...where,
          [Op.and]: Utils.ilike('brand_rate_cards', 'name', filter.name),
        };
      }

      if (filter.rate_card_type) {
        where = {
          ...where,
          [Op.and]: Utils.ilike(
            'brand_rate_cards',
            'rate_card_type',
            filter.rate_card_type,
          ),
        };
      }

      if (filter.status) {
        where = {
          ...where,
          [Op.and]: Utils.ilike('brand_rate_cards', 'status', filter.status),
        };
      }

      if (filter.currency) {
        where = {
          ...where,
          [Op.and]: Utils.ilike(
            'brand_rate_cards',
            'currency',
            filter.currency,
          ),
        };
      }

      if (filter.discipline) {
        where = {
          ...where,
          [Op.and]: Utils.ilike(
            'brand_rate_cards',
            'discipline',
            filter.discipline,
          ),
        };
      }

      if (filter.output_channel) {
        where = {
          ...where,
          [Op.and]: Utils.ilike(
            'brand_rate_cards',
            'output_channel',
            filter.output_channel,
          ),
        };
      }

      if (filter.staff_skills) {
        where = {
          ...where,
          [Op.and]: Utils.ilike(
            'brand_rate_cards',
            'staff_skills',
            filter.staff_skills,
          ),
        };
      }

      if (filter.rate_card_owner) {
        where = {
          ...where,
          [Op.and]: Utils.ilike(
            'brand_rate_cards',
            'rate_card_owner',
            filter.rate_card_owner,
          ),
        };
      }

      if (filter.rate_card_id) {
        where = {
          ...where,
          [Op.and]: Utils.ilike(
            'brand_rate_cards',
            'rate_card_id',
            filter.rate_card_id,
          ),
        };
      }

      if (filter.markets) {
        where = {
          ...where,
          [Op.and]: Utils.ilike('brand_rate_cards', 'markets', filter.markets),
        };
      }

      if (filter.languages) {
        where = {
          ...where,
          [Op.and]: Utils.ilike(
            'brand_rate_cards',
            'languages',
            filter.languages,
          ),
        };
      }

      if (filter.version_number) {
        where = {
          ...where,
          [Op.and]: Utils.ilike(
            'brand_rate_cards',
            'version_number',
            filter.version_number,
          ),
        };
      }

      if (filter.commercial_owner) {
        where = {
          ...where,
          [Op.and]: Utils.ilike(
            'brand_rate_cards',
            'commercial_owner',
            filter.commercial_owner,
          ),
        };
      }

      if (filter.assumptions) {
        where = {
          ...where,
          [Op.and]: Utils.ilike(
            'brand_rate_cards',
            'assumptions',
            filter.assumptions,
          ),
        };
      }

      if (filter.no_fixed_text) {
        where = {
          ...where,
          [Op.and]: Utils.ilike(
            'brand_rate_cards',
            'no_fixed_text',
            filter.no_fixed_text,
          ),
        };
      }

      if (filter.yes_fixed_text) {
        where = {
          ...where,
          [Op.and]: Utils.ilike(
            'brand_rate_cards',
            'yes_fixed_text',
            filter.yes_fixed_text,
          ),
        };
      }

      if (filter.service_countRange) {
        const [start, end] = filter.service_countRange;

        if (start !== undefined && start !== null && start !== '') {
          where = {
            ...where,
            service_count: {
              ...where.service_count,
              [Op.gte]: start,
            },
          };
        }

        if (end !== undefined && end !== null && end !== '') {
          where = {
            ...where,
            service_count: {
              ...where.service_count,
              [Op.lte]: end,
            },
          };
        }
      }

      if (filter.valid_fromRange) {
        const [start, end] = filter.valid_fromRange;

        if (start !== undefined && start !== null && start !== '') {
          where = {
            ...where,
            valid_from: {
              ...where.valid_from,
              [Op.gte]: start,
            },
          };
        }

        if (end !== undefined && end !== null && end !== '') {
          where = {
            ...where,
            valid_from: {
              ...where.valid_from,
              [Op.lte]: end,
            },
          };
        }
      }

      if (filter.valid_toRange) {
        const [start, end] = filter.valid_toRange;

        if (start !== undefined && start !== null && start !== '') {
          where = {
            ...where,
            valid_to: {
              ...where.valid_to,
              [Op.gte]: start,
            },
          };
        }

        if (end !== undefined && end !== null && end !== '') {
          where = {
            ...where,
            valid_to: {
              ...where.valid_to,
              [Op.lte]: end,
            },
          };
        }
      }

      if (filter.review_dateRange) {
        const [start, end] = filter.review_dateRange;

        if (start !== undefined && start !== null && start !== '') {
          where = {
            ...where,
            review_date: {
              ...where.review_date,
              [Op.gte]: start,
            },
          };
        }

        if (end !== undefined && end !== null && end !== '') {
          where = {
            ...where,
            review_date: {
              ...where.review_date,
              [Op.lte]: end,
            },
          };
        }
      }

      if (filter.active !== undefined) {
        where = {
          ...where,
          active: filter.active === true || filter.active === 'true',
        };
      }

      if (filter.push_new_values) {
        where = {
          ...where,
          push_new_values: filter.push_new_values,
        };
      }

      if (filter.inherit_default_rate_card) {
        where = {
          ...where,
          inherit_default_rate_card: filter.inherit_default_rate_card,
        };
      }

      if (filter.createdAtRange) {
        const [start, end] = filter.createdAtRange;

        if (start !== undefined && start !== null && start !== '') {
          where = {
            ...where,
            ['createdAt']: {
              ...where.createdAt,
              [Op.gte]: start,
            },
          };
        }

        if (end !== undefined && end !== null && end !== '') {
          where = {
            ...where,
            ['createdAt']: {
              ...where.createdAt,
              [Op.lte]: end,
            },
          };
        }
      }
    }

    const queryOptions = {
      where,
      include,
      distinct: true,
      order:
        filter.field && filter.sort
          ? [[filter.field, filter.sort]]
          : [['createdAt', 'desc']],
      transaction: options?.transaction,
      logging: console.log,
    };

    if (!options?.countOnly) {
      queryOptions.limit = limit ? Number(limit) : undefined;
      queryOptions.offset = offset ? Number(offset) : undefined;
    }

    try {
      const { rows, count } = await db.brand_rate_cards.findAndCountAll(
        queryOptions,
      );

      return {
        rows: options?.countOnly ? [] : rows,
        count: count,
      };
    } catch (error) {
      console.error('Error executing query:', error);
      throw error;
    }
  }

  static async findAllAutocomplete(query, limit, offset) {
    let where = {};

    if (query) {
      where = {
        [Op.or]: [
          { ['id']: Utils.uuid(query) },
          Utils.ilike('brand_rate_cards', 'id', query),
        ],
      };
    }

    const records = await db.brand_rate_cards.findAll({
      attributes: ['id', 'id'],
      where,
      limit: limit ? Number(limit) : undefined,
      offset: offset ? Number(offset) : undefined,
      orderBy: [['id', 'ASC']],
    });

    return records.map((record) => ({
      id: record.id,
      label: record.id,
    }));
  }
};
