//  Copyright (c) 2024 Huawei Technologies Co., Ltd.
//  openUBMC is licensed under Mulan PSL v2.
//  You can use this software according to the terms and conditions of the Mulan PSL v2.
//  You may obtain a copy of Mulan PSL v2 at:
//        #  http://license.coscl.org.cn/MulanPSL2
//  THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
//  EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
//  MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
//  See the Mulan PSL v2 for more details.
import { IOptions } from './../../models/storage-interface';
import { VolumeMembersModel } from '../../models/volume-create/volume-members.model';
import { computeCapacity, unitConversion } from '../../utils/storage.utils';
import { DriveCheckBox, AvailableCapacity, ICapacity, StorageTree, RaidType } from '../../models';

/**
 * 勾选物理盘触发--计算容量、容量单位、最大容量、最小容量
 */
export function autoCalculateByte(checkArr: any[], capacityNum: number, capacityOrigin: any) {
  let capacity: ICapacity;
  // 计算容量
  const autoSize = autoMinSize();
  const capacityValue = capacityNum > autoSize ? autoSize : capacityNum;
  if (checkArr && checkArr.length > 0) {
    const capacityObj = computeCapacity(capacityValue);
    capacity = {
      value: capacityObj.capacity,
      unit: capacityObj.unit,
      options: capacityOrigin.options,
      batyValue: capacityNum,
      oldValue: capacityNum,
    };
  } else {
    capacity = {
      value: null,
      unit: capacityOrigin.unit,
      options: capacityOrigin.options,
      batyValue: null,
      oldValue: null,
    };
  }
  // 计算和赋值最大容量、最小容量
  VolumeMembersModel.getInstance().setMinSize = autoSize;
  VolumeMembersModel.getInstance().setMaxSize = capacity.value as number;
  // 需要多个盘的raid级别未选择完成时，有计算出来负的容量值统一显示为0
  if (capacity.value && capacity.value < 0) {
    capacity.value = 0;
  }
  return capacity;
}

/**
 * 最小容量计算方法
 * a.Raid0所有盘容量较小的那个*盘个数
 * b.Raid1两个盘中容量较小的那个
 * c.Raid5勾选盘中容量较小的那个*(盘个数-1)
 * d.Raid6勾选盘中容量较小的那个*(盘个数-2)
 * e.Raid10勾选盘中容量较小的那个*(盘个数/2)
 * f.Raid50勾选盘中容量较小的那个*(盘个数 - 盘个数/每个Span的成员盘数)
 * g.Raid60勾选盘中容量较小的那个*(盘个数 - 盘个数*2/每个Span的成员盘数)
 * h.勾选“二级缓存”后，容量不可手动改变；不勾选可以修改容量，范围[64MB替换上面容量较小盘计算的值，以上计算的值]
 */
function autoMinSize(): number {
  const driveArr = VolumeMembersModel.getInstance().getCheckArr;
  const capacityArr = driveArr.filter(driveCheckBox => driveCheckBox.checked);
  const selectCount = capacityArr.length;
  if (selectCount === 0) {
    return 0;
  }
  // 获取勾选物理盘中的最小容量
  let minSizeBytes = Math.min.apply(
    Math,
    capacityArr.map(o => o.getCapacity),
  );
  const raidLevel = VolumeMembersModel.getInstance().getSelectData.volumeRaidLevel;
  const spanNum = VolumeMembersModel.getInstance().getSpanNum.value as number;
  const multipleMap: object = {
    0: selectCount,
    5: selectCount - 1,
    6: selectCount - 2,
    10: selectCount / 2,
    50: selectCount - (selectCount / spanNum),
    60: selectCount - (selectCount * 2) / spanNum,
  };
  const multiple = multipleMap[Number(raidLevel?.label as string)];
  if (multiple) {
    minSizeBytes = minSizeBytes * multiple;
  }
  return minSizeBytes;
}

/**
 * 创建逻辑盘--容量单位变化，计算容量的方法。
 * @param unit 容量单位
 */
export function unitChange(unit: string): number {
  const available = VolumeMembersModel.getInstance().getAvailableCapacity;
  let minSizeBytes: number;
  let capacity: number = 0;
  if (available && available.length > 0) {
    minSizeBytes = VolumeMembersModel.getInstance().availableSelect?.getBatyValue as number;
  } else {
    minSizeBytes = autoMinSize();
  }
  capacity = conversions(minSizeBytes, unit, 2);
  return capacity;
}
/**
 * 创建逻辑盘--用户手动改变容量
 * @param capacityInput 用户输入的容量值
 * @param unit 容量单位
 */
export function capacityChange(capacityInput: number, unit: string): number {
  const capacityNum = conversions(capacityInput, unit, 1);
  let capacity = 0;
  let allCapacity = 0;
  const available = VolumeMembersModel.getInstance().getAvailableCapacity;
  if (available && available.length > 0) {
    allCapacity = VolumeMembersModel.getInstance().availableSelect?.getBatyValue as number;
  } else {
    allCapacity = autoMinSize();
  }
  capacity = capacityNum >= allCapacity ? allCapacity : capacityNum;
  capacity = conversions(capacity, unit, 2);
  return capacity;
}

/**
 * 容量换算方法
 * @param value 容量数值
 * @param unit 容量单位
 * @param algorithm 算法方式，1是乘法，2是除法
 */
function conversions(value: number, unit: string, algorithm: number) {
  let capacity: number = 0;
  switch (unit) {
    case 'MB':
      capacity = unitConversion(value, 2, algorithm) as number;
      break;
    case 'GB':
      capacity = unitConversion(value, 3, algorithm) as number;
      break;
    case 'TB':
      capacity = unitConversion(value, 4, algorithm) as number;
      break;
    default:
      break;
  }
  return capacity;
}

/**
 * span成员组判定逻辑
 */
export function spanCount() {
  const selectCount = VolumeMembersModel.getInstance().getSelectData.drives?.length as number;
  const spanRange = VolumeMembersModel.getInstance().getSelectCount;
  if (!selectCount) {
    changeDriveDisable(false);
  } else if (selectCount >= spanRange.max) {
    changeDriveDisable(true);
  } else if (selectCount > 0 && selectCount < spanRange.max) {
    changeDriveDisable(false);
    const checkDrive = VolumeMembersModel.getInstance().getCheckArr.filter(
      driveBox => driveBox.getChecked,
    )[0];
    VolumeMembersModel.getInstance().getCheckArr.forEach(item => {
      if (item.getMediaType !== checkDrive.getMediaType) {
        item.setDisable = true;
      }
    });
  }
}
/**
 * 物理盘选中和容量计算方法
 * 1）遍历物理盘获取当前选中的物理盘数组
 * 2) 根据当前选中的物理盘数组初始化容量
 */
export function driveAndCapacityCount() {
  const volumeMembers = VolumeMembersModel.getInstance();
  const data = forEachDriveArr(volumeMembers.getCheckArr);
  volumeMembers.getSelectData.drives = data.checkArr || [];
  // 计算容量
  volumeMembers.setCapacityObj = autoCalculateByte(
    data.checkArr,
    data.capacityNum,
    volumeMembers.getCapacity,
  );
}

/**
 * 物理盘disable状态赋值方法
 * @param state 状态
 */
export function changeDriveDisable(state: boolean) {  
  const raidType = StorageTree.getInstance().getCheckedNode?.getRaidType || '';
  const driveArr = VolumeMembersModel.getInstance().getCheckArr;
  driveArr.forEach((drive: DriveCheckBox) => {
    const isAriesOnlineWithoutCapacity = drive.getFirmware === 'Online' && raidType === RaidType.ARIES && !drive.getAvailableCapacity;
    const isPmcWithOpoInitState = drive.getOpoInitState && raidType === RaidType.PMC;
    if (isAriesOnlineWithoutCapacity || isPmcWithOpoInitState) {
      drive.setDisable = true;
      return;
    }    
    drive.setDisable = state && !drive.checked ? state : drive.getIsDisable;
  });
}

/**
 * 物理盘的遍历方法，返回选中的物理盘数量、名称和容量
 * @param driveCheckArr 创建逻辑盘界面--物理盘数组
 */
export function forEachDriveArr(driveCheckArr: DriveCheckBox[]) {
  let capacityNum = 0;
  let selectCount = 0;
  let checkArr: any[] = [];
  driveCheckArr.forEach(item => {
    if (item.getChecked) {
      checkArr.push(item.getID);
      selectCount++;
      capacityNum += item.getCapacity;
    }
  });
  if (checkArr.length === 0) {
    checkArr = [];
  }
  return { checkArr, capacityNum, selectCount };
}

/**
 * 取消拥有盘组的物理盘选中状态
 * 1）isHaveRelated为true
 * 2）raid级别选中RAID0,不再置灰
 * 3）放开所有物理盘的Disablefang
 * 4) 计算物理盘和容量
 */
export function relateFalse() {
  const volumeMembers = VolumeMembersModel.getInstance();

  volumeMembers.isHaveRelated = false;
  volumeMembers.createRelated = false;

  // raid级别选中RAID0
  volumeMembers.setRAIDLevelSelect = volumeMembers.getRaidLevel.options[0];
  volumeMembers.setRaidLevelDisable = false;
  // 放开所有物理盘的Disablefang
  changeDriveDisable(false);
  // 计算物理盘和容量
  driveAndCapacityCount();

  // 清空可用容量
  volumeMembers.setAvailableCapacity = [];
}

/**
 * 选中拥有盘组的物理盘
 * 1）isHaveRelated为false
 * 2) raid级别、span成员盘数继承盘组的逻辑盘
 * 3）raid级别、span成员置灰不可编辑
 * 4）创建可用容量
 * 5) 容量初始化--可用容量的选中项
 * @param driveCheckBox 选中的物理盘
 */
export function relateTrue(driveCheckBox: DriveCheckBox) {
  const volumeMembers = VolumeMembersModel.getInstance();
  volumeMembers.isHaveRelated = true;
  volumeMembers.createRelated = true;

  // 盘容量未用完的物理盘为一个盘组，一个勾选本组均勾选，且级别、每个Span的成员盘数继承之前的逻辑盘
  volumeMembers.setRAIDLevelSelect = driveCheckBox.getRaidLevel as IOptions;
  volumeMembers.setSpanNum = driveCheckBox.getSpanNum;
  volumeMembers.setRaidLevelDisable = true;
  volumeMembers.setSpanNumDisable = true;

  // 创建可用容量
  if (driveCheckBox.getAvailableCapacity && driveCheckBox.getAvailableCapacity.length > 0) {
    createAvailable(driveCheckBox.getAvailableCapacity);
  }
  volumeMembers.getAvailableCapacity[0].checked = true;
  // 计算物理盘和容量
  driveAndCapacityCount();
  // 容量初始化--可用容量的选中项
  volumeMembers.setCapacityObj = {
    value: volumeMembers.availableSelect?.getValue as number | null,
    unit: volumeMembers.availableSelect?.getUnit as IOptions,
    options: volumeMembers.getCapacity.options,
    batyValue: volumeMembers.availableSelect?.getBatyValue as number | null,
    oldValue: null,
  };
}

/**
 * 创建可用容量
 * @param availableCapacity 指定驱动器阵列中的剩余容量（单位：MB）
 */
export function createAvailable(availableCapacity: number[]) {
  const volumeMembers = VolumeMembersModel.getInstance();
  availableCapacity.forEach(item => {
    volumeMembers.addAvailableCapacity(new AvailableCapacity(item));
  });
}
