import { LoginUser } from '@tomei/sso';
import { ProductProductCategoryRepository } from './product-product-category.repository';
import { ApplicationConfig } from '@tomei/config';
import { SettingsCategoryModel } from '../../entities/settings-category.entity';
import { ProductBase } from '../../base';
import { ProductCategory } from '../category-product/category-product';
import cuid from '../../helpers/cuid';
import { ActionEnum, Activity } from '@tomei/activity-history';
import { ObjectBase } from '@tomei/general';

export class ProductProductCategory extends ObjectBase {
  ObjectId: string;
  ObjectName: string;
  TableName: string;
  ObjectType = 'ProductProductCategory';
  private static _Repository = new ProductProductCategoryRepository();

  static async CheckProductAssignToCategory(
    Code: string,
    dbTransaction: any,
  ): Promise<boolean> {
    try {
      const options = {
        where: {
          Code: Code,
        },
        transaction: dbTransaction,
      };
      const result = await ProductProductCategory._Repository.findOne(options);
      if (result) {
        return true;
      } else {
        return false;
      }
    } catch (error) {
      throw error;
    }
  }

  static async listCategoryAssignedToProduct(
    ProductId: string,
    loginUser: LoginUser,
    page: number = 1,
    rows: number = 10,
    dbTransaction?: any,
  ): Promise<any> {
    const limit = rows;
    const offset = (page - 1) * rows;
    try {
      const systemCode =
        ApplicationConfig.getComponentConfigValue('system-code');
      const isPrivileged = await loginUser.checkPrivileges(
        systemCode,
        'Product - List Category',
      );
      if (!isPrivileged) {
        throw new Error('You do not have permission to list product category.');
      }

      const options = {
        where: {
          ProductId: ProductId,
        },
        include: [
          {
            model: SettingsCategoryModel,
          },
        ],
        distinct: true,
        limit,
        offset,
        transaction: dbTransaction,
      };

      const data =
        await ProductProductCategory._Repository.findAndCountAll(options);

      const result = {
        count: data.count,
        rows: data.rows.map((item: any) => {
          return {
            Code: item.Code,
            Name: item.Category.Name,
            Description: item.Category.Description,
            Status: item.Category.Status,
            ParentCode: item.Category.ParentCode,
            CodePath: item.Category.CodePath,
            CreatedAt: item.Category.CreatedAt,
            UpdatedAt: item.Category.UpdatedAt,
            CreatedById: item.Category.CreatedById,
            UpdatedById: item.Category.UpdatedById,
          };
        }),
      };

      return result;
    } catch (error) {
      throw error;
    }
  }

  static async assignProductToCategoryProduct(
    product: ProductBase,
    ProductCategory: ProductCategory,
    loginUser: LoginUser,
    dbTransaction?: any,
  ): Promise<any> {
    try {
      const systemCode =
        ApplicationConfig.getComponentConfigValue('system-code');
      const isPrivileged = await loginUser.checkPrivileges(
        systemCode,
        'Product - Assign Category',
      );
      if (!isPrivileged) {
        throw new Error(
          'You do not have permission to assign product category.',
        );
      }

      const ProductCategoryId = cuid();
      const options = {
        ProductCategoryId: ProductCategoryId,
        ProductId: product.ProductId,
        Code: ProductCategory.Code,
      };

      await ProductProductCategory._Repository.create(options, dbTransaction);

      const entityValueAfter = {
        ProductCategoryId: ProductCategoryId,
        ProductId: product.ProductId,
        Code: ProductCategory.Code,
      };

      const activity = new Activity();
      activity.ActivityId = cuid();
      activity.Action = ActionEnum.CREATE;
      activity.Description = 'Asssign Product to Category Product';
      activity.EntityType = 'ProductProductCategory';
      activity.EntityId = ProductCategoryId;
      activity.EntityValueBefore = JSON.stringify({});
      activity.EntityValueAfter = JSON.stringify(entityValueAfter);
      await activity.create(loginUser.ObjectId, dbTransaction);

      return {
        MessageCode: 'ProductCategoryAssigned',
        Message: 'Product added to Product Category.',
      };
    } catch (error) {
      throw error;
    }
  }

  static async unassignedProductFromCategory(
    product: ProductBase,
    ProductCategory: ProductCategory,
    loginUser: LoginUser,
    dbTransaction?: any,
  ): Promise<any> {
    try {
      const systemCode =
        ApplicationConfig.getComponentConfigValue('system-code');
      const isPrivileged = await loginUser.checkPrivileges(
        systemCode,
        'Product - Unassigned Category',
      );
      if (!isPrivileged) {
        throw new Error(
          'You do not have permission to unassign product category.',
        );
      }

      const options = {
        where: {
          ProductId: product.ProductId,
          Code: ProductCategory.Code,
        },
        transaction: dbTransaction,
      };

      const result = await ProductProductCategory._Repository.findOne(options);
      if (!result) {
        throw new Error('Product Category not found.');
      }

      await ProductProductCategory._Repository.delete(
        result.ProductCategoryId,
        dbTransaction,
      );

      const entityValueBefore = {
        ProductCategoryId: result.ProductCategoryId,
        ProductId: result.ProductId,
        Code: result.Code,
      };

      const activity = new Activity();
      activity.ActivityId = cuid();
      activity.Action = ActionEnum.DELETE;
      activity.Description = 'Unassign Product from Category Product';
      activity.EntityType = 'ProductProductCategory';
      activity.EntityId = result.ProductCategoryId;
      activity.EntityValueBefore = JSON.stringify(entityValueBefore);
      activity.EntityValueAfter = JSON.stringify({});
      await activity.create(loginUser.ObjectId, dbTransaction);

      return {
        MessageCode: 'ProductCategoryUnassigned',
        Message: 'Product unassigned from Product Category.',
      };
    } catch (error) {
      throw error;
    }
  }
}
