<?php
/**
 * CustomAstDB UCP widget.
 *
 * One widget instance per assigned extension (matches FreePBX core's
 * donotdisturb / callforward UCP pattern). Each widget shows DND toggle +
 * three Call Forward destination fields, scoped to that extension.
 *
 * Ownership gate: every read/write call validates via _checkExtension()
 * against the user's "assigned" extensions list. A POST that targets an
 * extension not in the user's assigned list is refused before any astdb
 * mutation.
 */

namespace UCP\Modules;
use \UCP\Modules as Modules;

#[\AllowDynamicProperties]
class Customastdb extends Modules {
    protected $module = 'Customastdb';
    private $user = null;
    private $userId = false;

    public function __construct($Modules) {
        $this->Modules = $Modules;
        $this->user    = $this->UCP->User->getUser();
        $this->userId  = $this->user ? $this->user['id'] : false;
    }

    public function getWidgetList() {
        return $this->getSimpleWidgetList();
    }

    public function getSimpleWidgetList() {
        $payload = [
            'rawname' => 'customastdb',
            'display' => _('AstDB State'),
            'icon'    => 'fa fa-database',
            'list'    => [],
        ];

        $err = $this->validate();
        if ($err['hasError']) {
            return array_merge($payload, $err);
        }

        $extensions = $this->UCP->getCombinedSettingByID($this->userId, 'Settings', 'assigned');
        $extensions = is_array($extensions) ? $extensions : [];

        $widgets = [];
        foreach ($extensions as $ext) {
            $data = $this->UCP->FreePBX->Core->getDevice($ext);
            if (empty($data) || empty($data['description'])) {
                $data = $this->UCP->FreePBX->Core->getUser($ext);
                $name = $data['name'] ?? '';
            } else {
                $name = $data['description'];
            }
            $widgets[$ext] = [
                'display'     => $name ?: ('Extension ' . $ext),
                'description' => sprintf(_('DND + Call Forward state for %s'), $name ?: $ext),
                'defaultsize' => ['height' => 4, 'width' => 2],
                'minsize'     => ['height' => 3, 'width' => 2],
            ];
        }
        $payload['list'] = $widgets;
        return $payload;
    }

    public function getWidgetDisplay($id) {
        $err = $this->validate($id);
        if ($err['hasError']) {
            return $err;
        }

        $state = $this->readState((string)$id);
        $displayvars = [
            'extension' => (string)$id,
            'dnd'       => $state['dnd'],
            'cf'        => $state['cf'],
            'cfb'       => $state['cfb'],
            'cfu'       => $state['cfu'],
        ];

        return [
            'title' => _('AstDB State'),
            'html'  => $this->load_view(__DIR__ . '/views/widget.php', $displayvars),
        ];
    }

    public function getSimpleWidgetSettingsDisplay($id) {
        return $this->getWidgetSettingsDisplay($id);
    }

    public function getWidgetSettingsDisplay($id) {
        return ['title' => _('AstDB State'), 'html' => ''];
    }

    public function poll($data) {
        $states = [];
        foreach ((array)$data as $ext) {
            if (!$this->_checkExtension($ext)) continue;
            $states[$ext] = $this->readState((string)$ext);
        }
        return ['states' => $states];
    }

    // =====================
    // AJAX gate + handler
    // =====================

    public function ajaxRequest($command, $settings) {
        // Every action takes an `ext` POST param — must match an assigned extension.
        $target = $_POST['ext'] ?? $_REQUEST['ext'] ?? '';
        if (empty($target) || !$this->_checkExtension($target)) {
            return false;
        }
        return in_array($command, ['setDnd', 'setCf', 'clearCf'], true);
    }

    public function ajaxHandler() {
        $cmd = $_REQUEST['command'] ?? '';
        $ext = $_POST['ext'] ?? '';
        if (!$this->_checkExtension($ext)) {
            return ['status' => false, 'message' => _('Permission denied — that extension is not assigned to you.')];
        }

        switch ($cmd) {
            case 'setDnd':
                $on = !empty($_POST['enabled']) && $_POST['enabled'] !== 'false' && $_POST['enabled'] !== '0';
                $this->UCP->FreePBX->Donotdisturb->setStatusByExtension($ext, $on ? 'YES' : '');
                return ['status' => true, 'alert' => 'success', 'message' => $on ? _('DND enabled.') : _('DND disabled.')];

            case 'setCf':
                $type   = strtoupper((string)($_POST['type'] ?? ''));
                $number = trim((string)($_POST['number'] ?? ''));
                if (!in_array($type, ['CF', 'CFB', 'CFU'], true)) {
                    return ['status' => false, 'message' => _('Unknown CF type.')];
                }
                if ($number === '') {
                    $this->UCP->FreePBX->Callforward->delNumberByExtension($ext, $type);
                    return ['status' => true, 'alert' => 'success', 'message' => sprintf(_('%s cleared.'), $type)];
                }
                $this->UCP->FreePBX->Callforward->setNumberByExtension($ext, $number, $type);
                return ['status' => true, 'alert' => 'success', 'message' => sprintf(_('%s set to %s.'), $type, $number)];

            case 'clearCf':
                $this->UCP->FreePBX->Callforward->delAllNumbersByExtension($ext);
                return ['status' => true, 'alert' => 'success', 'message' => _('All Call Forwards cleared.')];

            default:
                return ['status' => false, 'message' => _('Unknown command.')];
        }
    }

    // =====================
    // Helpers
    // =====================

    /**
     * Read DND/CF state for a single extension via AMI helpers (always live —
     * sqlite has a 1-3s flush lag that would show stale values immediately
     * after a write, which the UCP poll would hit).
     */
    private function readState($extension) {
        $row = ['extension' => $extension, 'dnd' => false, 'cf' => '', 'cfb' => '', 'cfu' => ''];
        try {
            $dnd = $this->UCP->FreePBX->Donotdisturb->getStatusByExtension($extension);
            $row['dnd'] = ($dnd === 'YES');
        } catch (\Exception $e) {}
        try {
            $cf = $this->UCP->FreePBX->Callforward->getStatusesByExtension($extension);
            $row['cf']  = !empty($cf['CF'])  ? (string)$cf['CF']  : '';
            $row['cfb'] = !empty($cf['CFB']) ? (string)$cf['CFB'] : '';
            $row['cfu'] = !empty($cf['CFU']) ? (string)$cf['CFU'] : '';
        } catch (\Exception $e) {}
        return $row;
    }

    private function validate($extension = false) {
        $data = ['hasError' => false, 'errorMessages' => []];
        $extensions = $this->UCP->getCombinedSettingByID($this->userId, 'Settings', 'assigned');
        if (empty($extensions)) {
            $data['hasError'] = true;
            $data['errorMessages'][] = _('There are no extensions assigned to your account.');
        }
        if ($extension !== false) {
            if (empty($extension)) {
                $data['hasError'] = true;
                $data['errorMessages'][] = _('The given extension is empty.');
            }
            if (!$this->_checkExtension($extension)) {
                $data['hasError'] = true;
                $data['errorMessages'][] = _('That extension is not assigned to you.');
            }
        }
        return $data;
    }

    private function _checkExtension($extension) {
        $assigned = $this->UCP->getCombinedSettingByID($this->userId, 'Settings', 'assigned');
        $assigned = is_array($assigned) ? $assigned : [];
        return in_array((string)$extension, array_map('strval', $assigned), true);
    }
}
