<?php

namespace modules\selfserve\traits;
require_once WD . '/modules/selfserve/helpers/selfserve_lane_port.php';
require_once WD . '/modules/selfserve/classes/selfserve_lane.php';

use classes\shelly;
use modules\selfserve\helpers\selfserve_lane_port;
use modules\selfserve\helpers\selfserve_lane_log_action;
use modules\selfserve\helpers\selfserve_lane_state;
use modules\selfserve\helpers\selfserve_lane_status;
use modules\shelly\helpers\shelly_device_switch;
use modules\shelly\helpers\shelly_request_body_get_states;

trait selfserve_lane_port_controller_t
{
    /**
     * Open the lane port
     * @param selfserve_lane_port $port The port to open (ENTRANCE or EXIT)
     * @return bool True if the port was successfully opened, false otherwise
     * @throws \Exception If an invalid port is specified, or if the lane is not in a state to open the port
     */
    public function open(selfserve_lane_port $port): bool
    {
        // Require department lane object
        if (empty($this->department_lane)) throw new \Exception("Department lane object not found for lane ID {$this->id}");
        // Check lane status
        if ($this->status->equals(selfserve_lane_status::CLOSED)) throw new \Exception("Cannot open port on CLOSED lane");
        if ($this->status->equals(selfserve_lane_status::MAINTENANCE)) throw new \Exception("Cannot open port on MAINTENANCE lane");
        if ($this->status->equals(selfserve_lane_status::FAULT)) throw new \Exception("Cannot open port on FAULT lane");
        // Get the relay ID based on the port
        $relay_id = match ($port) {
            selfserve_lane_port::ENTRANCE => $this->department_lane->relay_out_id->value(),
            selfserve_lane_port::EXIT => $this->department_lane->relay_in_id->value(),
            default => throw new \Exception("Invalid port specified, must be ENTRANCE or EXIT"),
        };
        // Make sure relay ID is valid
        if (empty($relay_id)) {
            throw new \Exception("Invalid relay ID for port {$port->name}");
        }
        // Mark the lane state as opening the port
        $new_state = match ($port) {
            selfserve_lane_port::ENTRANCE => selfserve_lane_state::ENTRANCE_PORT_OPEN_QUEUED,
            selfserve_lane_port::EXIT => selfserve_lane_state::EXIT_PORT_OPEN_QUEUED,
            default => throw new \Exception("Invalid port specified, must be ENTRANCE or EXIT"),
        };
        $this->setLaneState($new_state);
        // Log the port open event
        $this->logLaneAction(selfserve_lane_log_action::OPEN_PORT, 200, ['port' => $port->name]);
        // Open the relay
        return $this->shellyOpenPort($port);
    }

    /**
     * Open the Shelly relay for the specified port
     * @param selfserve_lane_port $port The port to open (ENTRANCE or EXIT)
     * @return bool True if the relay was successfully opened
     * @throws \Exception If an invalid port is specified or if the relay ID is invalid
     */
    public function shellyOpenPort(selfserve_lane_port $port): bool
    {
        // Get the relay ID based on the port
        $relay_id = match ($port) {
            selfserve_lane_port::ENTRANCE => $this->department_lane->relay_out_id->value(),
            selfserve_lane_port::EXIT => $this->department_lane->relay_in_id->value(),
            default => throw new \Exception("Invalid port specified, must be ENTRANCE or EXIT"),
        };
        // Make sure relay ID is valid
        if (empty($relay_id)) {
            throw new \Exception("Invalid relay ID for port {$port->name}");
        }
        $shelly = new shelly();
        $shelly->requireModuleEnabled();
        $shelly->requireValidSecretKey();
        $parameters = new shelly_request_body_get_states();
        $parameters->ids = [$relay_id];
        $parameters->select = ['status'];
        $result = $shelly->sendPostRequest('/v2/devices/api/get', (array)$parameters);
        // Wait 1 second
        sleep(1);
        // Format the result
        $result = array_map(function ($device) {
            return (new shelly_device_switch())->populate($device);
        }, $result);
        // Open the switch
        foreach ($result as $device) {
            $device->switch(true);
        }
        return true;
    }
}