//  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 { isEmptyProperty } from '../../storage.service';
import { isEmptyBoolean, isEmptySwitch, getUnitConversionInt } from '../../utils/storage.utils';
import { IValue, IOptions, ISwitch, ISelect } from '../../models/storage-interface';
import { IChildData, Raid, DriveCheckBox, BBUModel, RaidType } from '../../models';
import $http from '@/utils/http-service';
import { traduction } from '@/utils/language';
import { StorageTree } from '../../models';
import { RaidNode } from '../../models/raid/raid-node.model';

const empty = '--';
function setHealth(severity: string, bodyData: any) {
  let health = '';
  if (!severity) {
    health = empty;
  } else if (severity === 'OK') {
    health = traduction('STORE_NORMAL');
  } else {
    health = `${traduction('STORE_ABNORMAL')}(${bodyData.FaultDetails})`;
  }
  return health;
}
function setRaidLevels(bodyData: any): IValue {
  let levels = null;
  if (isEmptyProperty(bodyData.SupportedRAIDTypes) && bodyData.SupportedRAIDTypes.length > 0) {
    levels = bodyData.SupportedRAIDTypes.filter((level: any) => {
      if (level.indexOf('RAID') > -1) {
        return level.substring(4, level.length);
      } else {
        return '';
      }
    });
  }
  const raidLevels: IValue = {
    name: 'IValue',
    label: levels ? `RAID(${levels.join('/').replace(/RAID/g, '')})` : empty,
    value: levels ? levels.join('/').replace(/RAID/g, '').split('/') : null,
  };
  return raidLevels;
}
function setbbuModel(bodyData: any): BBUModel | null {
  if (bodyData.BBU === null) {
    return null;
  }
  let bbuModel: BBUModel = new BBUModel('Absent', 'STORE_IN_POSITION', 'STORE_NORMAL');
  let position = empty;
  if (bodyData.BBU.State) {
    position = (bodyData.BBU.State === 'Absent' || bodyData.BBU.State === 255) ? 
      'STORE_NO_IN_POSITION' : 
      'STORE_IN_POSITION';
  }
  let bbuHealth = bodyData.BBU.Health;
  if (bodyData.BBU.State === 'Absent' || bodyData.BBU.State === 255) {
    bbuHealth = null;
  } else if (!bbuHealth) {
    bbuHealth = empty;
  } else if (bbuHealth === 'OK' || bbuHealth === 'Informational') {
    bbuHealth = traduction('STORE_NORMAL');
  } else {
    const detail = bodyData.BBU.FaultDetails || empty;
    bbuHealth = `${traduction('STORE_ABNORMAL')}(${detail})`;
  }
  bbuModel = new BBUModel(bodyData.BBU.Name || empty, position, bbuHealth);
  return bbuModel;
}
function setChildData(bodyData: any): IChildData {
  return {
    volumeSupport: bodyData.VolumeSupported,
    oobSupport: bodyData.OOBSupport,
    maxSize: bodyData.MaxStripeSizeBytes,
    minSize: bodyData.MinStripeSizeBytes,
    readPolicyConfig: bodyData.ReadPolicy?.Configurable,
    writePolicyConfig: bodyData.WritePolicy?.Configurable,
    IOPolicyConfig: bodyData.CachePolicy?.Configurable,
    drivePolicyConfig: bodyData.DriveCachePolicy?.Configurable,
    accessPolicyConfig: bodyData.AccessPolicy?.Configurable,
  };
}
function setStripSizeRange(bodyData: any): string {
  return (isEmptyNumber(bodyData.MinStripeSizeBytes) &&
    isEmptyNumber(bodyData.MaxStripeSizeBytes)) ?
    `${getUnitConversionInt(bodyData.MinStripeSizeBytes || 0)} - ${getUnitConversionInt(bodyData.MaxStripeSizeBytes || 0)}` :
    empty;
}
function setCopyback(bodyData: any): any {
  return isEmptySwitch(bodyData.CopyBackState,
    { name: 'ISwitch', id: true, label: 'STORE_ENABLED', state: false },
    { name: 'ISwitch', id: false, label: 'STORE_DISABLED', state: false },
  ) || { name: 'ISwitch', id: false, label: '--', state: false };
}
function setSmartErrors(bodyData: any): any {
  return isEmptySwitch(bodyData.SmarterCopyBackState,
    { name: 'ISwitch', id: true, label: 'STORE_ENABLED', state: false },
    { name: 'ISwitch', id: false, label: 'STORE_DISABLED', state: false },
  ) || { name: 'ISwitch', id: false, label: '--', state: false };
}
function setJbodModel(bodyData: any): any {
  return isEmptySwitch(
    bodyData.JBODState,
    { name: 'ISwitch', id: true, label: 'STORE_ENABLED', state: false },
    { name: 'ISwitch', id: false, label: 'STORE_DISABLED', state: false },
  ) || { name: 'ISwitch', id: false, label: '--', state: false };
}
function setParm(bodyData: any): any {
  const name = isEmptyProperty(bodyData.Name) || empty;
  const sn = isEmptyProperty(bodyData.SerialNumber) || empty;
  const type = isEmptyProperty(bodyData.Type);
  const firmwareVersion = isEmptyProperty(bodyData.FirmwareVersion) || empty;
  const bandManag = isEmptyBoolean(bodyData.OOBSupport, 'COMMON_YES', 'COMMON_NO') || empty;
  const raidLevels = setRaidLevels(bodyData);
  const mode = isEmptyProperty(bodyData.Mode) || empty;
  const configVersion = isEmptyProperty(bodyData.ConfigurationVersion) || empty;
  const memorySize = isEmptyProperty(bodyData.MemorySizeMiB, ' MB') || empty;
  return { name, sn, type, firmwareVersion, bandManag, raidLevels, mode, configVersion, memorySize };
}
export function factory(raidNode: RaidNode, url: string): Promise<any> {
  return new Promise((resolve, reject) => {
    getData(url).then((data: any): void => {
      const bodyData = data.data;
      if (!bodyData) {
        return;
      }
      const { name, sn, type, firmwareVersion, bandManag, raidLevels, mode, configVersion, memorySize } = setParm(bodyData);
      let health = isEmptyProperty(bodyData.Health) || empty;
      const severity = bodyData.Health;
      health = setHealth(severity, bodyData);
      const deviceProtocols = isEmptyProperty(bodyData.SupportedDeviceProtocols) || 0;
      const speedGbps = isEmptyProperty(bodyData.SpeedGbps) || 0;
      const deviceInter = deviceProtocols && speedGbps ? `${deviceProtocols} ${speedGbps} GB` : empty;
      const sasAddress = isEmptyProperty(bodyData.SASAddress) || empty;
      const stripSizeRange = setStripSizeRange(bodyData);
      const cachePinned =
        isEmptyBoolean(bodyData.CachePinnedState, 'COMMON_YES', 'COMMON_NO') || empty;
      const faultMemory = 
        isEmptyBoolean(bodyData.MaintainPDFailHistory, 'STORE_ENABLED', 'STORE_DISABLED') || empty;
      const driverName = bodyData.DriverInfo ? isEmptyProperty(bodyData.DriverInfo.DriverName) : null;
      const driverVersion = bodyData.DriverInfo ? isEmptyProperty(bodyData.DriverInfo.DriverVersion) : null;
      const copyback = setCopyback(bodyData);
      const smartErrors = setSmartErrors(bodyData);
      const jbodModel = setJbodModel(bodyData);
      const _raidNode = StorageTree.getInstance().getParentRaidById(bodyData.ID);      
      const jbodShow = _raidNode?.jbodStateSupported;
      const childData: IChildData = setChildData(bodyData);
      const driveArr: DriveCheckBox[] = getCheckBoxArr(bodyData.Drives);
      const foreignConfigStatus = !getForeignConfigStatus(bodyData.Drives);
      let bbuModel = setbbuModel(bodyData);
      const modes = getModes(bodyData.SupportedModes);
      sessionStorage.setItem('JBODState', bodyData.JBODState);
      const raidType = raidNode.getRaidType;
      let autoRepairEnabled = null;
      let completedVolumeCount = null;
      let delayForStart = null;
      let enabled = null;
      let period = null;
      let rate = null;
      let runningStatus = null;
      let totalVolumeCount = null;      
      if (bodyData.ConsisCheckInfo) {
        autoRepairEnabled = bodyData.ConsisCheckInfo.AutoRepairEnabled;
        completedVolumeCount = bodyData.ConsisCheckInfo.CompletedVolumeCount;
        delayForStart = bodyData.ConsisCheckInfo.DelayForStart.toString();
        enabled = bodyData.ConsisCheckInfo.Enabled;
        period = bodyData.ConsisCheckInfo.Period;
        rate = bodyData.ConsisCheckInfo.Rate;
        runningStatus = bodyData.ConsisCheckInfo.RunningStatus;
        totalVolumeCount = bodyData.ConsisCheckInfo.TotalVolumeCount;
      }
      const noBBUWrite = isEmptyBoolean(bodyData.NoBatteryWriteCacheEnabled, 'true', 'false');
      const pcieLinkWidth = isEmptyNumber(bodyData.PCIeLinkWidth) ? bodyData.PCIeLinkWidth : empty;
      const readCache = isEmptyProperty(bodyData.ReadCachePercent, '%');
      const spareActivationMode = isEmptyProperty(bodyData.SpareActivationMode);
      const writeCachePolicy = `${isEmptyProperty(bodyData.WriteCachePolicy?.ConfiguredDrive) || empty}/
        ${isEmptyProperty(bodyData.WriteCachePolicy?.UnconfiguredDrive) || empty}/
        ${isEmptyProperty(bodyData.WriteCachePolicy?.HBADrive) || empty}`;
      const bootDevices = bodyData.BootDevices?.length > 0 ? bodyData.BootDevices?.join('/') : null;
      const writeCacheData = bodyData.WriteCachePolicy || null;
      resolve(
        new Raid(name, sn, type, firmwareVersion, bandManag, health, raidLevels, mode, configVersion, memorySize,
          deviceInter, sasAddress, stripSizeRange, cachePinned, faultMemory, driverName, driverVersion, copyback,
          smartErrors, jbodModel, jbodShow, childData, driveArr, bbuModel, foreignConfigStatus, modes, _raidNode.epdSupported, raidType,
          enabled, delayForStart, runningStatus, period, autoRepairEnabled, completedVolumeCount, totalVolumeCount,
          rate, pcieLinkWidth, bootDevices, _raidNode.jbodStateSupported, noBBUWrite, readCache, spareActivationMode,
          writeCachePolicy, writeCacheData,
        ),
      );
    });
  });
}

function getraidType(raidType: string): string {
  let raidTypeTemp = '';  
  let specials8iBoard: boolean = false;
  if (raidType && String(raidType)?.indexOf('MSCC') > -1) {
    raidTypeTemp = RaidType.PMC;
    if (raidType && String(raidType) === 'MSCC SmartHBA 2100-8i') {
      raidTypeTemp = RaidType.HBA;
    }
  } else if (raidType && String(raidType)?.startsWith('SP')) {
    raidTypeTemp = RaidType.ARIES;
  } else {
    raidTypeTemp = RaidType.BRCM;
    if (
      raidType?.includes('9560-8i') ||
      raidType?.includes('9560-16i') ||
      raidType?.includes('SAS3908')
    ) {
      specials8iBoard = true;
    }
  }
  return raidTypeTemp;
}

export function getData(url: string): Promise<any> {
  return $http.get(url);
}

export function isEmptyNumber(val: number): boolean {
  if (val === 0 || isEmptyProperty(val)) {
    return true;
  }
  return false;
}

export function getCheckBoxArr(drives: any[]): DriveCheckBox[] {
  const driveArr: DriveCheckBox[] = [];
  if (drives && drives.length > 0) {
    drives.forEach((drive: any) => {
      const members = drive.Members ? drive.Members : null;
      const level = drive.VolumeRaidLevel ? {
        name: 'IOptions',
        id: drive.VolumeRaidLevel,
        label: drive.VolumeRaidLevel.replace(/RAID/g, ''),
      } : null;
      driveArr.push(
        new DriveCheckBox(
          drive.ID,
          drive.DriveID,
          drive.Name,
          drive.FreeSpaceMiBPerDrive === 0 || drive.FreeSpaceMiBPerDrive ?
            drive.FreeSpaceMiBPerDrive * 1024 * 1024 : drive.CapacityBytes,
          members,
          drive.MediaType,
          drive.Protocol,
          drive.SSDCachecadeVolume,
          drive.FirmwareStatus,
          level,
          drive.NumDrivePerSpan,
          drive.FreeBlocksSpaceMiB?.length === 0 ? [drive.TotalFreeSpaceMiB] : drive.FreeBlocksSpaceMiB,
          drive.IsEPD,
          drive.TotalFreeSpaceMiB || 0,
        ),
      );
    });
  }
  driveArr.forEach((driveCheck: DriveCheckBox) => {
    let related: DriveCheckBox[] = [];
    if (driveCheck.getRelatedName && driveCheck.getRelatedName.length > 0) {
      driveCheck.getRelatedName.map(item => {
        related.push(driveArr.filter(obj => obj.getDriveID === item)[0]);
      });
    } else {
      related = [];
    }
    driveCheck.setRelated = related;
  });

  return driveArr;
}

export function getForeignConfigStatus(drives: any[]): boolean {
  if (drives && drives.length > 0) {
    const state = drives.filter(drive => drive.FirmwareStatus === 'Foreign');
    return state[0] ? true : false;
  }
  return false;
}

export function getModes(supportedModes: any[]): IOptions[] | null {
  const options: IOptions[] | null = supportedModes && supportedModes.length > 0 ? supportedModes.map(
    (_mode: any) => {
      return {
        name: 'IOptions',
        id: String(_mode),
        label: String(_mode),
      };
    },
  ) : null;
  return options;
}
export function reset(): Promise<any> {
  const node = StorageTree.getInstance().getCheckedNode || StorageTree.getInstance().getFoliages[0];
  const url = `/UI/Rest/System/Storage/${node?.id}/RestoreDefaultSettings`;
  return $http.post(url, {});
}
// 	导入Foreign配置
export function foreignConfig(): Promise<any> {
  const node = StorageTree.getInstance().getCheckedNode;
  const url = `/UI/Rest/System/Storage/${node?.id}/ImportForeignConfig`;
  return $http.post(url, {});
}

// 	清除Foreign配置
export function clearForeignConfig(): Promise<any> {
  const node = StorageTree.getInstance().getCheckedNode;
  const url = `/UI/Rest/System/Storage/${node?.id}/ClearForeignConfig`;
  return $http.post(url, {});
}