-- Copyright 2022 SmartThings
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
--     http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.

local capabilities = require "st.capabilities"
local cc = require "st.zwave.CommandClass"
local CentralScene = (require "st.zwave.CommandClass.CentralScene")({ version = 1 })
local SwitchBinary = (require "st.zwave.CommandClass.SwitchBinary")({ version = 2 })
local SwitchMultilevel = (require "st.zwave.CommandClass.SwitchMultilevel")({ version = 4 })
local Version = (require "st.zwave.CommandClass.Version")({ version = 2 })
local constants = require "st.zwave.constants"
local log = require "log"

local PROFILE_CHANGED = "profile_changed"
local LAST_SEQ_NUMBER_KEY = -1

local BUTTON_VALUES = {
  "up_hold", "down_hold", "held",
  "up", "up_2x", "up_3x", "up_4x", "up_5x",
  "down", "down_2x", "down_3x", "down_4x", "down_5x",
  "pushed", "pushed_2x", "pushed_3x", "pushed_4x", "pushed_5x"
}

local map_key_attribute_to_capability = {
  [CentralScene.key_attributes.KEY_PRESSED_1_TIME] = {
    [0x01] = capabilities.button.button.up(),
    [0x02] = capabilities.button.button.down(),
    [0x03] = capabilities.button.button.pushed()
  },
  [CentralScene.key_attributes.KEY_PRESSED_2_TIMES] = {
    [0x01] = capabilities.button.button.up_2x(),
    [0x02] = capabilities.button.button.down_2x(),
    [0x03] = capabilities.button.button.pushed_2x()
  },
  [CentralScene.key_attributes.KEY_PRESSED_3_TIMES] = {
    [0x01] = capabilities.button.button.up_3x(),
    [0x02] = capabilities.button.button.down_3x(),
    [0x03] = capabilities.button.button.pushed_3x()
  },
  [CentralScene.key_attributes.KEY_PRESSED_4_TIMES] = {
    [0x01] = capabilities.button.button.up_4x(),
    [0x02] = capabilities.button.button.down_4x(),
    [0x03] = capabilities.button.button.pushed_4x()
  },
  [CentralScene.key_attributes.KEY_PRESSED_5_TIMES] = {
    [0x01] = capabilities.button.button.up_5x(),
    [0x02] = capabilities.button.button.down_5x(),
    [0x03] = capabilities.button.button.pushed_5x()
  },
  [CentralScene.key_attributes.KEY_HELD_DOWN] = {
    [0x01] = capabilities.button.button.up_hold(),
    [0x02] = capabilities.button.button.down_hold(),
    [0x03] = capabilities.button.button.held()
  }
}

local ZOOZ_ZEN_30_DIMMER_RELAY_FINGERPRINTS = {
  { mfr = 0x027A, prod = 0xA000, model = 0xA008 } -- Zooz Zen 30 Dimmer Relay Double Switch
}

local function version_report_handler(driver, device, cmd)
  if (cmd.args.firmware_0_version > 1 or (cmd.args.firmware_0_version == 1 and cmd.args.firmware_0_sub_version > 4)) and
    device:get_field(PROFILE_CHANGED) ~= true then
    local new_profile = "zooz-zen-30-dimmer-relay-new"
    device:try_update_metadata({ profile = new_profile })
    device:set_field(PROFILE_CHANGED, true, { persist = true })
  end
end

local function can_handle_zooz_zen_30_dimmer_relay_double_switch(opts, driver, device, ...)
  if device.network_type == "DEVICE_EDGE_CHILD" then return false end --is child device
  for _, fingerprint in ipairs(ZOOZ_ZEN_30_DIMMER_RELAY_FINGERPRINTS) do
    if device:id_match(fingerprint.mfr, fingerprint.prod, fingerprint.model) then
      local subdriver = require("zooz-zen-30-dimmer-relay")
      return true, subdriver
    end
  end
  return false
end

local function central_scene_notification_handler(driver, device, cmd)
  if (cmd.args.key_attributes == 0x01) then
    log.error("Button Value 'released' is not supported by SmartThings")
    return
  end

  if device:get_field(LAST_SEQ_NUMBER_KEY) ~= cmd.args.sequence_number then
    device:set_field(LAST_SEQ_NUMBER_KEY, cmd.args.sequence_number)
    local event_map = map_key_attribute_to_capability[cmd.args.key_attributes]
    local event = event_map and event_map[cmd.args.scene_number]
    if event ~= nil then
      device:emit_event_for_endpoint(cmd.src_channel, event)
    end
  end
end

local function added_handler(driver, device)
  device:emit_event(capabilities.button.supportedButtonValues(BUTTON_VALUES))
  device:emit_event(capabilities.button.numberOfButtons({ value = 3 }))
end

local function do_refresh(driver, device)
  device:send_to_component(SwitchMultilevel:Get({}), "main")
  device:send_to_component(SwitchBinary:Get({}), "switch1")
  device:send(Version:Get({}))
end

local function switch_set_on_off_handler(value)
  return function(driver, device, command)
    local get, set

    if command.component == "main" then
      set = SwitchMultilevel:Set({ value = value, duration = constants.DEFAULT_DIMMING_DURATION })
      get = SwitchMultilevel:Get({})
    elseif command.component == "switch1" then
      set = SwitchBinary:Set({ target_value = value, duration = 0 })
      get = SwitchBinary:Get({})
    end

    local query_device = function()
      device:send_to_component(get, command.component)
    end

    device:send_to_component(set, command.component)
    device.thread:call_with_delay(constants.DEFAULT_GET_STATUS_DELAY, query_device)
  end
end

local zooz_zen_30_dimmer_relay_double_switch = {
  NAME = "Zooz Zen 30",
  capability_handlers = {
    [capabilities.refresh.ID] = {
      [capabilities.refresh.commands.refresh.NAME] = do_refresh
    },
    [capabilities.switch.ID] = {
      [capabilities.switch.switch.on.NAME] = switch_set_on_off_handler(SwitchBinary.value.ON_ENABLE),
      [capabilities.switch.switch.off.NAME] = switch_set_on_off_handler(SwitchBinary.value.OFF_DISABLE)
    }
  },
  zwave_handlers = {
    [cc.CENTRAL_SCENE] = {
      [CentralScene.NOTIFICATION] = central_scene_notification_handler
    },
    [cc.VERSION] = {
      [Version.REPORT] = version_report_handler
    }
  },
  lifecycle_handlers = {
    added = added_handler
  },
  can_handle = can_handle_zooz_zen_30_dimmer_relay_double_switch
}

return zooz_zen_30_dimmer_relay_double_switch
