//  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, true, 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, {});
}