<?php declare(strict_types=1);
/**
 * @author Ryan Spaeth <rspaeth@spaethtech.com>
 * @copyright 2025 - Spaeth Technologies, Archous Networks
 */

namespace SpaethTech\UCRM\SDK;

use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
use SpaethTech\UCRM\SDK\Configs\PluginAuth;
use SpaethTech\UCRM\SDK\Configs\PluginConfig;
use SpaethTech\UCRM\SDK\Configs\PluginManifest;
use SpaethTech\UCRM\SDK\Configs\PluginUcrm;
use SpaethTech\UCRM\SDK\Security\Crypto;

final class Plugin
{
  public function __construct(
    private readonly Server $server,
    private string $basePath = __DIR__ . "/../"
  ) {
    $this->basePath = realpath($this->basePath);
  }

  public function getServer(): Server
  {
    return $this->server;
  }

  public function getLogger(): Logger
  {
    // create a log channel
    $logger = new Logger("plugin");
    $logger->pushHandler(new StreamHandler(
      $this->getPath("data", "plugin.log"),
      Logger::DEBUG
    ));

    return $logger;
  }

  public function clearLog(string $message = ""): self
  {
    file_put_contents($this->getPath("data/plugin.log"), "$message\n");
    return $this;
  }

  public function getPath(string ...$parts): string
  {
    return $this->basePath . "/" . implode("/", $parts);
  }

  #region CONFIGS

  public function getConfig(): PluginConfig
  {
    return new PluginConfig($this);
  }

  public function getUcrm(): PluginUcrm
  {
    return new PluginUcrm($this);
  }

  public function getManifest(): PluginManifest
  {
    return new PluginManifest($this);
  }

  public function getAuth(): PluginAuth
  {
    return new PluginAuth($this);
  }

  #endregion

  public function getId(): int
  {
    return $this->getUcrm()->getPluginId();
  }

  public function getName(): string
  {
    return $this->getManifest()->get("information")["name"];
  }

  public function getVersion(): string
  {
    return $this->getManifest()->get("information")["version"];
  }

  public function getPublicUrl(): string
  {
    return $this->getServer()->getPublicUrl() .
      "/crm/_plugins/{$this->getName()}/public";
  }



  #region CRYPTO

  public function encrypt(array|string $data): string
  {
    if (is_array($data))
      $data = json_encode($data);

    return Crypto::encrypt($data, $this->getAuth()->getCryptoPassword());
  }

  public function decrypt(string $data): string
  {
    return Crypto::decrypt($data, $this->getAuth()->getCryptoPassword());
  }

  #endregion

  public function getTextFile(string $path): false|string
  {
    return file_get_contents($this->getPath($path));
  }

  public function putTextFile(
    string $path,
    string $contents,
    bool $final_newline = true
  ): self {
    file_put_contents(
      $this->getPath($path),
      $contents . ($final_newline ? "\n" : "")
    );
    return $this;
  }

  public function getJsonFile(
    string $path,
    ?bool $associative = null,
    int $depth = 512,
    int $flags = 0
  ): array {
    return json_decode(
      file_get_contents($this->getPath($path)),
      $associative,
      $depth,
      $flags
    );
  }

  public function putJsonFile(
    string $path,
    array|string $contents,
    bool $final_newline = true,
    int $flags = JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES,
    int $depth = 512
  ): self {
    file_put_contents(
      $this->getPath($path),
      json_encode($contents, $flags, $depth) .
      ($final_newline ? "\n" : "")
    );

    return $this;
  }


  public function getProvisionerClient(): Client
  {
    var_dump("{$this->getConfig()->get("provisioner_url")}/api/v2/");
    return new Client([
      "base_uri" => "{$this->getConfig()->get("provisioner_url")}/api/v2/",
      "headers" => [
          "X-UISP-Instance-ID" => $this->getServer()->getInstanceId(),
          "X-UISP-Hostname" => $this->getServer()->getHostname(),
          "X-Auth-Token" => $this->getAuth()->getXAuthToken(),
          "Content-Type" => "application/json",
        ]
    ]);
  }

  public function getWorkflowClient(): Client
  {
    return new Client([
      "base_uri" => "{$this->getConfig()->get("provisioner_url")}/api/v2/webhook/",
      "headers" => [
          "X-UISP-Instance-ID" => $this->getServer()->getInstanceId(),
          "X-UISP-Hostname" => $this->getServer()->getHostname(),
          "X-Auth-Token" => $this->getAuth()->getXAuthToken(),
          "Content-Type" => "application/json",
        ],
    ]);
  }



  public function executeWorkflow(
    string $workflow,
    array $extra = [],
    bool $wait = false
  ): array|false {
    $logger = $this->getLogger();

    try {
      $client = $this->getWorkflowClient();
      $server = $this->getServer();

      $response = $client->put($workflow . ($wait ? "?wait" : ""), [
        "json" => [
          ...[
            "instance_id" => $server->getInstanceId(),
            "hostname" => $server->getHostname(),
            "plugin_id" => $this->getId(),
            "unms_api_url" => $server->getPublicUnmsApiUrl(),
            "unms_api_key" => $server->getUnmsToken(),
            "ucrm_api_url" => $server->getPublicUcrmApiUrl(),
            "ucrm_api_key" => $server->getUcrmToken(),

            // TODO: Add any other required data here...
          ],
          ...$extra
        ]
      ]);

      return json_decode($response->getBody()->getContents(), true);
    } catch (GuzzleException $e) {
      $logger->error("Workflow Response", [
        "workflow" => $workflow,
        "error" => $e->getMessage(),
      ]);
      return false;
    }
  }


}
