<?php

namespace onespace\tools\activeApi\components\clients;

use Exception;
use onespace\tools\activeApi\components\clients\teams\actions\TeamsActions;
use onespace\tools\activeApi\components\clients\teams\OneSpaceService;
use onespace\tools\activeApi\components\clients\teams\TeamsMessageComponent;
use Yii;
use yii\helpers\ArrayHelper;
use yii\httpclient\Client;
use yii\httpclient\Request;

/**
 * This client allows the sending of teams alerts to predefined teams channels. By casting this class to a string
 * it can be hooked into the Yii logging system (see __toString() to see how to do that)
 *
 * @author Gareth Palmer <gareth@one-space.co.za>
 */
final class TeamAlertClient extends Client {
    /** This one is for spamming test messages, when setting things up */
    public const string TEST_WEBHOOK = "https://defaultede491d326034d56beb1f38ffd43a5.7f.environment.api.powerplatform.com:443/powerautomate/automations/direct/workflows/404bfb8211c44e7b9829f1567aba3b42/triggers/manual/paths/invoke?api-version=1&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&sig=sqfJ5Q0xnlC5TQ4ro1FKdfcjaChiOiQiNFNwaXTPeaQ";
    public const string ONEACCESS_WEBHOOK = "https://defaultede491d326034d56beb1f38ffd43a5.7f.environment.api.powerplatform.com:443/powerautomate/automations/direct/workflows/e09998725e28400298520fe440ebd4e4/triggers/manual/paths/invoke?api-version=1&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&sig=xMIYJwzRcFpiHOPhjqNar_kLk2xB1HQq1yjwB2x8bzU";
    public const string ONEDEVICE_WEBHOOK = "https://defaultede491d326034d56beb1f38ffd43a5.7f.environment.api.powerplatform.com:443/powerautomate/automations/direct/workflows/1dfd6349e6ce4ca78d3db01e5be0d329/triggers/manual/paths/invoke?api-version=1&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&sig=J_l3oQRJxOk0kCFoA0WP9Ez_PBAfZ4V52AUk4v7Nxiw";
    public const string AUTH_WEBHOOK = "https://defaultede491d326034d56beb1f38ffd43a5.7f.environment.api.powerplatform.com:443/powerautomate/automations/direct/workflows/2094d9f7f0574122b2d31164015eb82b/triggers/manual/paths/invoke?api-version=1&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&sig=yOGG03HNBbFUSMKSNFVusHvEt10n7rNfw75QZeOa1Yc";
    public const string CONNECT_WEBHOOK = "https://defaultede491d326034d56beb1f38ffd43a5.7f.environment.api.powerplatform.com:443/powerautomate/automations/direct/workflows/e6038442211049e9b49b9d8793b87e61/triggers/manual/paths/invoke?api-version=1&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&sig=J6GBrKPpQBhu-7rgR5AAZtXxw9_aLzylj1VG0d_Bo_o";
    public const string CENTRAL_WEBHOOK = "https://defaultede491d326034d56beb1f38ffd43a5.7f.environment.api.powerplatform.com:443/powerautomate/automations/direct/workflows/87b18bf69ae448378517e82a68e87207/triggers/manual/paths/invoke?api-version=1&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&sig=V3CffX5S7qe9EaKry8ZNKY6hU9HaTustuD6T1qppS-g";

    private OneSpaceService $service;

    /**
     * @return Request request instance.
     * @throws \yii\base\InvalidConfigException
     */
    #[\Override]
    public function createRequest() {
        $config = $this->requestConfig;
        if (!isset($config['class'])) {
            $config['class'] = Request::class;
        }
        $config['client'] = $this;
        /** @var Request $request */
        $request = Yii::createObject($config);
        $request->setFormat(Client::FORMAT_JSON);

        return $request;
    }

    /** Required for hooking logging these alerts to file under their correct service */
    public function setService(OneSpaceService $service): void {
        $this->service = $service;
    }

    /**
     * Single line static method for firing an alert when logging. Returns the `TeamAlertClient` object cast to string
     * for easy Yii based logging.
     */
    public static function sendAlert(OneSpaceService $service, TeamsMessageComponent ...$components): string {
        $client = new self();
        $client->setService($service);

        $url = match ($service) {
            OneSpaceService::DEVELOPMENT => self::TEST_WEBHOOK,
            OneSpaceService::ONEACCESS => self::ONEACCESS_WEBHOOK,
            OneSpaceService::ONEDEVICE => self::ONEACCESS_WEBHOOK,
            OneSpaceService::AUTH      => self::AUTH_WEBHOOK,
            OneSpaceService::CONNECT   => self::CONNECT_WEBHOOK,
            OneSpaceService::CENTRAL   => self::CENTRAL_WEBHOOK,
            default => throw new Exception("Invalid Alert Endpoint"),
        };

        $payload = $client->generatePayload($components);
        $client->genericSend($url, $payload);

        return (string)$client;
    }

    /**
     * Generate the actual JSON (as an array) payload to send to Teams.
     *
     * @param TeamsMessageComponent[] $components
     */
    public function generatePayload(array $components): array {
        $body = $actions = [];
        foreach ($components as $component) {
            if ($component instanceof TeamsActions) {
                $actions[] = $component->build();
                continue;
            }
            $body[] = $component->build();
        }
        if (count($actions) > 0) {
            $body[] = [
                "type" => "ActionSet",
                "actions" => $actions,
            ];
        }

        $payload = [
            'attachments' => [
                [
                    'content' => [
                        'body' => $body,
                        '$schema' => "http://adaptivecards.io/schemas/adaptive-card.json",
                        'type' => "AdaptiveCard",
                        'version' => "1.4",
                        'msTeams' => ["width" => "Full"],
                    ],
                    "contentType" => "application/vnd.microsoft.card.adaptive",
                ],
            ],
        ];

        return $payload;
    }

    /**
     * Send a teams message to a parsed endpoint.
     */
    public function genericSend(string $url, array $payload): \yii\httpclient\Response {
        Yii::info(json_encode($payload, JSON_PRETTY_PRINT), __METHOD__);
        // print_r(json_encode($payload, JSON_PRETTY_PRINT));
        return $this->post($url, $payload, ['Content-Type' => 'application/json'])->send();
    }

    /**
     * Send a teams message to the Testing channel Notification Panel
     */
    public function sendToTest(TeamsMessageComponent ...$components): void {
        $payload = $this->generatePayload($components);
        $this->setService(OneSpaceService::DEVELOPMENT);
        $this->genericSend(self::TEST_WEBHOOK, $payload);
    }

    /**
     * Send a teams message to OneAccess on the OneAccess Notification Panel
     */
    public function sendToOneAccess(TeamsMessageComponent ...$components): void {
        $payload = $this->generatePayload($components);
        $this->setService(OneSpaceService::ONEACCESS);
        $this->genericSend(self::ONEACCESS_WEBHOOK, $payload);
    }

    /**
     * Send a teams message to OneAccess on the OneAccess Notification Panel
     */
    public function sendToOneDevice(TeamsMessageComponent ...$components): void {
        $payload = $this->generatePayload($components);
        $this->setService(OneSpaceService::ONEDEVICE);
        $this->genericSend(self::ONEDEVICE_WEBHOOK, $payload);
    }

    /**
     * Send a teams message to Auth on the Auth Notification Panel
     */
    public function sendToAuth(TeamsMessageComponent ...$components): void {
        $payload = $this->generatePayload($components);
        $this->setService(OneSpaceService::AUTH);
        $this->genericSend(self::AUTH_WEBHOOK, $payload);
    }

    /**
     * Send a teams message to Auth on the Auth Notification Panel
     */
    public function sendToConnect(TeamsMessageComponent ...$components): void {
        $payload = $this->generatePayload($components);
        $this->setService(OneSpaceService::CONNECT);
        $this->genericSend(self::CONNECT_WEBHOOK, $payload);
    }

    /**
     * Send a teams message to Auth on the Auth Notification Panel
     */
    public function sendToCentral(TeamsMessageComponent ...$components): void {
        $payload = $this->generatePayload($components);
        $this->setService(OneSpaceService::CENTRAL);
        $this->genericSend(self::CENTRAL_WEBHOOK, $payload);
    }

    /**
     * This should allow you to alert using `Yii::info()` / `Yii::warning` / `Yii::error` when casting
     * this object to string.
     *
     * ## Example
     *
     * ```php
     * Yii::error(
     *      "The System is borked",
     *      TeamAllertClient::sendAlert(
     *          OneSpaceService::ONEACCESS
     *          new TeamsTextBlock(
     *              text: "Alert",
     *              color: TextColour::ATTENTION,
     *              size: TextSize::LARGE,
     *              weight: TextWeight::BOLDER
     *          ),
     *      ),
     * );
     * ```
     */
    public function __toString() {
        // Generate a Service name based on the alert being generated
        $serviceName = match ($this->service) {
            OneSpaceService::ONEACCESS => 'OneAccess',
            OneSpaceService::ONEDEVICE => 'OneDevice',
            OneSpaceService::AUTH      => 'Auth',
            OneSpaceService::CONNECT   => 'Connect',
            OneSpaceService::CENTRAL   => 'Central',
            default => 'Generic',
        } . "TeamsAlert";


        if (ArrayHelper::getValue(Yii::$app->getLog()->targets, $serviceName) != null) {
            return $serviceName;
        }

        $targetConfig = [
            'class' => \yii\log\FileTarget::class,
            'logFile' => "@logs/alerts/{$serviceName}",
            'levels' => ['info', 'error', 'warning'],
            'logVars' => [],
            'categories' => [$serviceName],
        ];

        Yii::$app->getLog()->targets[$serviceName] = Yii::createObject($targetConfig);

        return $serviceName;
    }
}
