import {NativeModules, Platform} from 'react-native'
import {NativeResult, Result} from '../models/modules/Result'
import { TYSdk } from 'tuya-panel-kit'
interface LDVDevicePanelManager {
  back: () => void
  control: (params: any, callback: (result: any) => void) => void
  setTimer: (params: any, callback: (result: any) => void) => void
  getAllTaskTimer: (deviceId: string, type: number, callback: (res: NativeResult<string>) => void) => void
  deleteDevice: (deviceId: string, isReset: boolean, callback: (result: any) => void) => void
  rename: (deviceId: string, name: string, callback: (result: any) => void) => void
  toDeviceSettingsPage: (deviceId: string, isGroup: boolean) => void
  toRoutinesPage: (params: {backTitle:string, deviceId:string}) => void
  putJson: (deviceId: string, featureType: string, json: string, callback: (res: NativeResult<any>) => void) => void
  getJson: (deviceId: string, featureType: string, callback: (res: NativeResult<string>) => void) => void
  getInitiativeQueryDpsInfoWithDpsArray: (dpIds: string, deviceId: string, callback: (res: NativeResult<string>) => void) => void
  openDownloadFile: (filePath: string) => void
  formatNumber: (num: number, fixed: number, isCN: boolean) => string
  getTimeZone: () => string
  groupControl: (tyGroupId: number, dps: string, config: string) => Promise<NativeResult<any>>
  groupControlToTuya: (tyGroupId: number, dps: string) => Promise<NativeResult<any>>
  groupControlToEzviz: (tyGroupId: number, config: string) => Promise<NativeResult<any>>
  getFeature: (deviceId: string, featureId: string, callback: (res: NativeResult<string>) => void) => void
  putFeature: (deviceId: string, featureId: string, value: any, callback: (res: NativeResult<string>) => void) => void
  getGroupDevices: (tyGroupId: number) => Promise<NativeResult<string>>
  getSystemTimeFormat: () => Promise<number>
  getMicrophoneAccess: (res:any) => Promise<Result<any>>
  firebaseEvent: (dimensions:Record<any, any>) => Promise<NativeResult<any>>
  appEvent: (action: string, payload: Record<string, any>) => void
}

export enum UADeviceCategory {
  ThirdParty = 'ThirdParty',
  General = 'General',
  LightSource = 'LightSource',
  CeilingLight = 'CeilingLight',
  CeilingFan = 'CeilingFan',
  SterilizedCeilingFan = 'SterilizedCeilingFan',
  PIRLight = 'PIRLight',
  SolarLight = 'SolarLight',
  StringLights = 'StringLights',
  StripLights = 'StripLights',
  PowerStrip = 'PowerStrip',
  NightlightPlug = 'NightlightPlug',
  WifiPlug = 'WifiPlug',
  ChildLockPlug = 'ChildLockPlug',
  RepeaterSocket = 'RepeaterSocket',
  ContactSensor = 'ContactSensor',
  MotionDetector = 'MotionDetector',
  PIRCamera = 'PIRCamera',
  LinkageCamera = 'LinkageCamera',
  SmartCamera = 'SmartCamera',
  MatterLight = 'MatterLight',
  MeshLight = 'MeshLight',
  MeshSwitch = 'MeshSwitch',
}

export interface DeviceInfo {
  deviceId: string
  deviceName: string
  deviceIcon: string
  tyPid: string
  deviceCategory: UADeviceCategory
  roomName: string
  status: number
  dps: string
  tuyaDeviceId: string
}

const devicePanel: LDVDevicePanelManager = NativeModules.LDVDevicePanelManager
const logManager = NativeModules.RNLogManager

const back = () => {
  devicePanel.back()
}

const log = (str: string) => {
  logManager.log(str)
}

const showObj = (objc) => {
  if (!!objc) {
    logManager.objc(objc)
  }
}


const control = (devId, dps, callback) => {
  devicePanel.control({devId, dps: JSON.stringify(dps)}, res => {
    callback && callback(res)
  })
}

// timer
const TASK = 'LDV_TY'

const timerList = devId => {
  return new Promise((resolve, _reject) => {
    const params = {devId, task: TASK, action: 'list', bizType: 0}
    devicePanel.setTimer(params, res => {
      resolve(res)
    })
  })
}

const addTimer = (devId, value, callback: any = undefined) => {
  const params = {devId, task: TASK, action: 'add', value, bizType: 0}
  devicePanel.setTimer(params, res => {
    callback && callback(res)
  })
}

const editTimer = (devId, value, callback: any = undefined) => {
  const params = {devId, task: TASK, action: 'update', value, bizType: 0}
  devicePanel.setTimer(params, res => {
    callback && callback(res)
  })
}

const deleteTimer = (devId, value, callback: any = undefined) => {
  const params = {devId, task: TASK, action: 'delete', value, bizType: 0}
  devicePanel.setTimer(params, res => {
    callback && callback(res)
  })
}

/**
 * 获取所有Timer，不区分TASK
 * @param devId 涂鸦 设备 ID 或群组 ID
 * @param type 0:设备，1:群组
 * @param callback
 */
function getAllTaskTimer(devId: string, type: number = 0, callback: ((res: NativeResult<string>) => void)) {
  devicePanel.getAllTaskTimer(devId, type, callback)
}

const setDp = <T>(deviceId: string, key: string, value: any) => {
  return new Promise<NativeResult<T>>((resolve, _reject) => {
    control(deviceId, {[key]: value}, res => {
      resolve(res)
    })
  })
}

const setDps = <T>(deviceId: string, dps: any) => {
  return new Promise<NativeResult<T>>((resolve, _reject) => {
    control(deviceId, dps, res => {
      resolve(res)
    })
  })
}

type GetFeatureResultType = (deviceId: string, featureId: string) => Promise<NativeResult<any>>;
type SetFeatureResultType = (
  deviceId: string,
  featureId: string,
  value: any,
) => Promise<NativeResult<any>>;

export const getFeature: GetFeatureResultType = (deviceId: string, featureId: string) => {
  return new Promise((resolve, _reject) => {
    devicePanel.getFeature(deviceId, featureId, res => {
      const result: NativeResult<any> = {
        ...res,
        data: !!res.data ? JSON.parse(res.data).value : null,
      }
      resolve(result)
    })
  })
}

export const putFeature: SetFeatureResultType = (
  deviceId: string,
  featureId: string,
  value: any,
) => {
  return new Promise((resolve, _reject) => {
    devicePanel.putFeature(deviceId, featureId, JSON.stringify({value}), res => {
      resolve(res)
    })
  })
}

export const sendAppEvent = (action: string, payload?: Record<string, any>) => {
  try {
    console.log(action, payload)
    devicePanel.appEvent(action, payload ?? {})
  } catch (e) {
    console.log('sendAppEvent', e)
  }
}

type DeleteDeviceResultType = (deviceId: string, isReset: boolean) => Promise<NativeResult<any>>

const deleteDevice: DeleteDeviceResultType = (deviceId: string, isReset: boolean) => {
  return new Promise((resolve, _reject) => {
    devicePanel.deleteDevice(deviceId, isReset, res => {
      resolve(res)
    })
  })
}

type RenameResultType = (deviceId: string, name: string) => Promise<NativeResult<any>>

const rename: RenameResultType = (deviceId: string, name: string) => {
  return new Promise((resolve, _reject) => {
    devicePanel.rename(deviceId, name, res => {
      resolve(res)
    })
  })
}

function toDeviceSettingsPage(tuyaDeviceId: string, isGroup: boolean = false) {
  devicePanel.toDeviceSettingsPage(tuyaDeviceId, isGroup)
}

function toRoutinesPage(params: {backTitle:string, deviceId:string}) {
  devicePanel.toRoutinesPage(params)
}

export class NativeApi {
  static back(): void {
    back()
  }

  static log(msg: string): void {
    log(msg)
  }

  static logObj(msg: any): void {
    this.log(JSON.stringify(msg))
  }

  static showObj(obj: any): void {
    showObj(obj)
  }

  static getAllTaskTimer(devId: string, type: number = 0): Promise<Result<any>> {
    return new Promise<Result<any>>((resolve, _reject) => {
      getAllTaskTimer(devId, type, res => {
        const allList = JSON.parse(res.data || '[]')
          .map(item => item.mTimerList)
          .flat();
        resolve({
          success: res.result,
          data: res.result ? allList : undefined,
          msg: res.msg,
        })
      })
    })
  }

  static timerList(deviceId: string): Promise<any> {
    return timerList(deviceId)
  }

  static addTimer(deviceId: string, value: any, callback?: (res: any) => void): void {
    addTimer(deviceId, value, callback)
  }

  static editTimer(deviceId: string, value: any, callback?: (res: any) => void): void {
    editTimer(deviceId, value, callback)
  }

  static deleteTimer(deviceId: string, value: any, callback?: (res: any) => void): void {
    deleteTimer(deviceId, value, callback)
  }

  static manageTimer(devId: string, timer: any, mode: 'add' | 'delete' | 'update'){
    return new Promise<Result<any>>((resolve) =>{
      const params = {devId, task: TASK, action: mode, value: timer, bizType: 0}
      devicePanel.setTimer(params, res => {
        resolve({
          success: res.result,
          data: res.data,
          msg: res.msg
        })
      })
    })
  }

  static setDp<T>(deviceId: string, key: string, value: any): Promise<NativeResult<T>> {
    return setDp<T>(deviceId, key, value)
  }

  static setDps<T>(deviceId: string, dps: any): Promise<NativeResult<T>> {
    return setDps<T>(deviceId, dps)
  }

  static deleteDevice(deviceId: string, isReset: boolean): Promise<NativeResult<any>> {
    return deleteDevice(deviceId, isReset)
  }

  static renameDevice(deviceId: string, name: string): Promise<NativeResult<any>> {
    return rename(deviceId, name)
  }

  static toDeviceSettingsPage(deviceId: string, isGroup: boolean = false): void {
    toDeviceSettingsPage(deviceId, isGroup)
  }

  static toRoutinesPage(params: {backTitle:string, deviceId:string}): void{
    toRoutinesPage(params)
  }

  static putJson(deviceId: string, featureType: string, json: string): Promise<Result<any>> {
    return new Promise<Result<any>>(resolve => {
      devicePanel.putJson(deviceId, featureType, json, nativeRes => {
        resolve({
          success: nativeRes.result,
          data: nativeRes.data,
          msg: nativeRes.msg,
        })
      })
    })
  }

  static getJson(deviceId: string, featureType: string): Promise<Result<any>> {
    return new Promise<Result<any>>(resolve => {
      devicePanel.getJson(deviceId, featureType, nativeRes => {
        resolve({
          success: nativeRes.result,
          data: nativeRes.data,
          msg: nativeRes.msg,
        })
      })
    })
  }

  static async groupControl(tyGroupId: number, dps: string, config: string): Promise<Result<any>> {
    const nativeResult = await devicePanel.groupControl(tyGroupId, dps, config)
    return {
      success: nativeResult.result,
      msg: nativeResult.msg,
      data: nativeResult.data,
    }
  }

  static async getGroupDevices(tyGroupId: number): Promise<Result<DeviceInfo[]>> {
    const nativeResult = await devicePanel.getGroupDevices(tyGroupId)
    return {
      success: nativeResult.result,
      msg: nativeResult.msg,
      data: nativeResult.data && JSON.parse(nativeResult.data),
    }
  }

  static async putGroupTYDps(tyGroupId: number, dps: string){
    const nativeResult = await devicePanel.groupControlToTuya(tyGroupId, dps)
    return {
      success: nativeResult.result,
      msg: nativeResult.msg,
      data: nativeResult.data,
    }
  }

  static async putGroupEzvizConfig(tyGroupId: number, config: string){
    const nativeResult = await devicePanel.groupControlToEzviz(tyGroupId, config)
    return {
      success: nativeResult.result,
      msg: nativeResult.msg,
      data: nativeResult.data,
    }
  }

  static async putFlagFirebase(dimensions: Record<any, any>){
    const nativeResult = await devicePanel.firebaseEvent({
      eventName: 'select_country_flag',
      dimensions
    })
    return {
      success: nativeResult.result,
      msg: nativeResult.msg,
    }
  }
}

// 打开下载文件
export const openDownloadFile = (filePath: string) => {
  return new Promise((_reject) => {
    devicePanel.openDownloadFile(filePath)
  })
}

export const queryDpIds = (dpIds: string, deviceId: string) => {
  return new Promise((resolve, _reject) => {
    devicePanel.getInitiativeQueryDpsInfoWithDpsArray(dpIds, deviceId, res => {
      resolve(res)
    })
  })
}

export const formatNumber: (num: number, fixed: number, shoGroup?: boolean) => string = (num, fixed, shoGroup: boolean = true) => {
  const res = devicePanel.formatNumber(num, fixed, shoGroup)
  log(`formatNumber: num=${num}, fixed=${fixed}, res=${res}`)
  return res
}

export const getTimeZone = async (): Promise<string> => {
  return new Promise((resolve) => {
    const timeZone = Platform.OS === 'android' ? devicePanel.getTimeZone() || 'Europe/Berlin' : Intl.DateTimeFormat().resolvedOptions().timeZone
    resolve(timeZone)
  })
}

// 获取手机系统设置的12小时制还是24小时制
export const getSystemTimeFormat = async (): Promise<number> => {
  try {
    return await devicePanel.getSystemTimeFormat()
  } catch (_) {
    return 24
  }
}

export const getMicrophoneAccess: () => Promise<boolean> = () => {
  return new Promise((resolve, _reject) => {
      devicePanel.getMicrophoneAccess(res => {
        const haveAuthority = (typeof res?.data === 'string') ? !!res?.data && JSON.parse(res?.data)?.haveAuthority : res?.data?.haveAuthority
        if(!res.result || (res.result && haveAuthority !== 'granted')){
          resolve(false)
        }
        resolve(true)
      })
  })
}

export const getTuyaCloudData = (devId: string): Promise<Record<string, any>> => {
  return new Promise((resolve, reject) => {
    TYSdk.native.apiRNRequest(
      {
        a: 's.m.dev.property.get',
        postData: {
          devId: devId,
          bizType: 0,
        },
        v: '2.0'
      },
      (d: string) => {
        const data = typeof d === 'string' ? JSON.parse(d) : d;
        resolve(data);
      },
      (err: string) => {
        reject(err);
      }
    )
  })
}
