<?php

/**
 * Code for Hub Account Model
 *
 * @package northmill-online-shared
 */
declare (strict_types=1);
namespace Northmill_Online_Shared_Checkout\Northmill_Online_Shared\Abstracts\Hub_API\Hub_Accounts\Models;

use Northmill_Online_Shared_Checkout\Northmill_Online_Shared\Abstract_Shared_Base;
use Northmill_Online_Shared_Checkout\Northmill_Online_Shared\Abstracts\Data_Model;
use Northmill_Online_Shared_Checkout\Northmill_Online_Shared\Abstracts\Hub_API\API;
use Northmill_Online_Shared_Checkout\Northmill_Online_Shared\Abstracts\Hub_API\Main_API;
use Northmill_Online_Shared_Checkout\Northmill_Online_Shared\Abstracts\Hub_API\Stock_API;
use Northmill_Online_Shared_Checkout\Northmill_Online_Shared\Modules\Loggers\Log_Level_Enum;
use Throwable;
defined('ABSPATH') || exit;
/**
 * Hub model.
 */
class Hub_Account_Model extends Data_Model
{
    /**
     * The WordPress ID of the Hub account.
     *
     * @var int
     */
    public int $wp_id;
    /**
     * Allows disabling of Hub accounts, without deleting them.
     *
     * @var bool
     */
    public bool $enabled;
    /**
     * The name of the Hub account to be displayed in frontend.
     *
     * @var string
     */
    public string $display_name;
    /**
     * URL to the Hub account API.
     *
     * @var string
     */
    public string $url;
    /**
     * Username for the Hub account.
     *
     * @var string
     */
    public string $user;
    /**
     * Password for the Hub account.
     *
     * @var string
     */
    public string $pass;
    /**
     * The type of the Hub account. Can be string 'main' or 'stock'.
     *
     * @var string
     */
    public string $type;
    /**
     * The environment of the Hub account. Can be string 'prod' or 'test'.
     *
     * @var string
     */
    public string $env;
    /**
     * Allowed shipping methods for the Hub account.
     * Strings of "[zone_id]:[method_id]:[method_instance_id]".
     *
     * @var string[]
     */
    public array $allowed_shipping_methods;
    /**
     * The organization number of the Hub account.
     *
     * @var string
     */
    public string $org_num;
    /**
     * The organization name of the Hub account.
     *
     * @var string
     */
    public string $org_name;
    /**
     * The last time the Hub account was synced.
     *
     * @var string
     */
    public string $last_sync;
    /**
     * Article account codes for the Hub account.
     *
     * @var Article_Account_Code_Model[]
     */
    private array $article_account_codes;
    /**
     * Article account codes for the Hub account.
     *
     * @var Income_Account_Code_Model[]
     */
    private array $income_account_codes;
    /**
     * VAT account codes for the Hub account.
     *
     * @var Vat_Account_Code_Model[]
     */
    private array $vat_account_codes;
    /**
     * Shipping settings.
     *
     * @var Shipping_Model
     */
    private Shipping_Model $shipping_settings;
    /**
     * The SKU of the article used for partial refunds.
     *
     * @var string
     */
    public string $partial_refund_article_sku;
    /**
     * The inherited class of API for the Hub account.
     *
     * @var API
     */
    public API $api;
    /**
     * Constructs the Hub account model.
     *
     * @param array $args            Model properties.
     * @param bool  $instantiate_api Whether to instantiate the API class.
     */
    public function __construct(array $args = array(), bool $instantiate_api = \true)
    {
        parent::__construct($args);
        if ($instantiate_api) {
            if ($this->is_main()) {
                $this->api = new Main_API(null, $this);
            } elseif ($this->is_stock()) {
                $this->api = new Stock_API($this);
            } else {
                Abstract_Shared_Base::base_instance()->logger->log('hub-accounts', 'Invalid Hub account type. Could not instantiate API.', array('account' => $this->get_account_basics_for_logging()), Log_Level_Enum::ERROR);
            }
        }
    }
    /**
     * Get the title of the Hub account.
     * This is used in the admin area, and not in the front-end, since it might return API URL.
     */
    public function get_title(): string
    {
        if ($this->has_string_property_value('display_name')) {
            return $this->display_name;
        } elseif ($this->has_string_property_value('org_name')) {
            return $this->org_name;
        } elseif ($this->has_string_property_value('url')) {
            return $this->url;
        } else {
            return '';
        }
    }
    /**
     * Check if the property has a non-empty string value.
     *
     * @param string $property The property to check.
     *
     * @return bool
     */
    private function has_string_property_value(string $property): bool
    {
        return !empty($this->{$property}) && is_string($this->{$property}) && !empty(trim($this->{$property}));
    }
    /**
     * Get display name property for usage in the front-end.
     *
     * @return string
     */
    public function get_display_name(): string
    {
        return !empty($this->display_name) ? $this->display_name : $this->org_name ?? '';
    }
    /**
     * Check if the account is enabled.
     * Main accounts are always enabled.
     *
     * @return bool Whether the account is enabled. Defaults to true.
     */
    public function is_enabled(): bool
    {
        return $this->is_main() || ($this->enabled ?? \true);
    }
    /**
     * Check if the account is a test account.
     *
     * @return bool
     */
    public function is_test(): bool
    {
        return 'test' === $this->env;
    }
    /**
     * Check if the account is a main account.
     *
     * @return bool
     */
    public function is_main(): bool
    {
        return 'main' === $this->type;
    }
    /**
     * Check if the account is a stock account.
     *
     * @return bool
     */
    public function is_stock(): bool
    {
        return 'stock' === $this->type;
    }
    /**
     * Get article account codes property.
     *
     * @return Article_Account_Code_Model[]
     */
    public function get_article_account_codes(): array
    {
        return $this->article_account_codes ?? array();
    }
    /**
     * Set article account codes property.
     *
     * @param mixed $article_account_codes Article account codes.
     */
    public function set_article_account_codes(mixed $article_account_codes): void
    {
        $this->article_account_codes = $this->get_account_codes_value(Article_Account_Code_Model::class, $article_account_codes);
    }
    /**
     * Get income account codes property.
     *
     * @return Income_Account_Code_Model[]
     */
    public function get_income_account_codes(): array
    {
        return $this->income_account_codes ?? array();
    }
    /**
     * Set income account codes property.
     *
     * @param mixed $income_account_codes Article account codes.
     */
    public function set_income_account_codes(mixed $income_account_codes): void
    {
        $this->income_account_codes = $this->get_account_codes_value(Income_Account_Code_Model::class, $income_account_codes);
    }
    /**
     * Get vat account codes property.
     *
     * @return Vat_Account_Code_Model[]
     */
    public function get_vat_account_codes(): array
    {
        return $this->vat_account_codes ?? array();
    }
    /**
     * Get VAT account code based on VAT percentage.
     *
     * @param int $vat_percentage The VAT percentage.
     *
     * @return int|null The VAT account code, or null if not found.
     */
    public function get_vat_account_code(int $vat_percentage): ?int
    {
        $vat_codes = $this->get_vat_account_codes();
        if (!empty($vat_codes)) {
            if (isset($vat_codes[$vat_percentage])) {
                return $vat_codes[$vat_percentage]->get_account_code();
            }
        }
        return null;
    }
    /**
     * Set vat account codes property.
     *
     * @param mixed $vat_account_codes Article account codes.
     */
    public function set_vat_account_codes(mixed $vat_account_codes): void
    {
        $this->vat_account_codes = $this->get_account_codes_value(Vat_Account_Code_Model::class, $vat_account_codes);
    }
    /**
     * Get validated article account codes value of the specified type.
     *
     * @param string $account_code_model_name Name of the account code model class.
     * @param mixed  $value                   Value to validate.
     *
     * @return array
     */
    private function get_account_codes_value(string $account_code_model_name, mixed $value): array
    {
        if (is_array($value)) {
            foreach ($value as $key => $article_account_code) {
                if (!is_a($article_account_code, $account_code_model_name)) {
                    unset($value[$key]);
                }
            }
        } else {
            $value = array();
        }
        return $value;
    }
    /**
     * Get shipping settings property.
     *
     * @return Shipping_Model
     */
    public function get_shipping_settings(): Shipping_Model
    {
        return $this->shipping_settings ?? new Shipping_Model();
    }
    /**
     * Set shipping settings property.
     *
     * @param mixed $shipping_settings Shipping settings.
     *
     * @return void
     */
    public function set_shipping_settings(mixed $shipping_settings): void
    {
        if (is_array($shipping_settings)) {
            try {
                $shipping_settings = new Shipping_Model($shipping_settings);
            } catch (Throwable $e) {
                Abstract_Shared_Base::base_instance()->logger->log('hub-accounts', 'Failed to set shipping settings', array('shipping-settings' => $shipping_settings, 'account' => $this->get_account_basics_for_logging(), 'error' => $e->getMessage()), Log_Level_Enum::ERROR);
            }
        }
        if (is_a($shipping_settings, Shipping_Model::class)) {
            $this->shipping_settings = $shipping_settings;
        }
    }
    /**
     * Get the account basics for logging.
     *
     * @return array
     */
    public function get_account_basics_for_logging(): array
    {
        return array('wp_id' => $this->wp_id, 'display_name' => $this->display_name, 'url' => $this->url, 'user' => $this->user, 'password_set' => !empty($this->pass), 'type' => $this->type, 'env' => $this->env, 'org_num' => $this->org_num, 'org_name' => $this->org_name, 'last_sync' => $this->last_sync, 'enabled' => $this->enabled);
    }
    /**
     * Get the account information for logging.
     *
     * @return array
     */
    public function get_account_for_logging(): array
    {
        return array('wp_id' => $this->wp_id, 'display_name' => $this->display_name, 'url' => $this->url, 'user' => $this->user, 'password_set' => !empty($this->pass), 'type' => $this->type, 'env' => $this->env, 'org_num' => $this->org_num, 'org_name' => $this->org_name, 'last_sync' => $this->last_sync, 'enabled' => $this->enabled, 'allowed_shipping_methods' => $this->allowed_shipping_methods, 'partial_refund_article_sku' => $this->partial_refund_article_sku, 'article_account_codes' => $this->get_article_account_codes(), 'income_account_codes' => $this->get_income_account_codes(), 'vat_account_codes' => $this->get_vat_account_codes(), 'shipping_settings' => $this->get_shipping_settings());
    }
    /**
     * Disconnects the Hub account.
     * Removing it from the DB.
     *
     * @return bool
     */
    public function disconnect(): bool
    {
        return (bool) wp_delete_post($this->wp_id, \true);
    }
}
