<?php

/**
 * @author WP Cloud Plugins
 * @copyright Copyright (c) 2023, WP Cloud Plugins
 *
 * @since       2.0
 * @see https://www.wpcloudplugins.com
 */

namespace TheLion\UseyourDrive;

defined('ABSPATH') || exit;

class Accounts
{
    /**
     * The single instance of the class.
     *
     * @var Accounts
     */
    protected static $_instance;

    /**
     * $_accounts contains all the accounts that are linked with the plugin.
     *
     * @var \TheLion\UseyourDrive\Account[]
     */
    private $_accounts = [];

    public function __construct()
    {
        $this->_init_accounts();
    }

    /**
     * Accounts Instance.
     *
     * Ensures only one instance is loaded or can be loaded.
     *
     * @return Accounts - Accounts instance
     *
     * @static
     */
    public static function instance()
    {
        if (is_null(self::$_instance)) {
            self::$_instance = new self();
        }

        return self::$_instance;
    }

    /**
     * @return bool
     */
    public function has_accounts()
    {
        return count($this->_accounts) > 0;
    }

    /**
     * @return \TheLion\UseyourDrive\Account[]
     */
    public function list_accounts()
    {
        return $this->_accounts;
    }

    /**
     * @return null|\TheLion\UseyourDrive\Account
     */
    public function get_primary_account()
    {
        if (0 === count($this->_accounts)) {
            return null;
        }

        $first_account = reset($this->_accounts);

        if (false === $first_account->get_authorization()->has_access_token()) {
            return null;
        }

        return $first_account;
    }

    /**
     * @param string $id
     *
     * @return null|\TheLion\UseyourDrive\Account
     */
    public function get_account_by_id($id)
    {
        if (false === isset($this->_accounts[(string) $id])) {
            return null;
        }

        return $this->_accounts[(string) $id];
    }

    /**
     * @param mixed $email
     *
     * @return null|\TheLion\UseyourDrive\Account
     */
    public function get_account_by_email($email)
    {
        foreach ($this->_accounts as $account) {
            if ($account->get_email() === $email) {
                return $account;
            }
        }

        return null;
    }

    /**
     * @return $this
     */
    public function add_account(Account $account)
    {
        $this->_accounts[$account->get_id()] = $account;

        $this->save();

        return $this;
    }

    /**
     * @param string $account_id
     *
     * @return $this
     */
    public function remove_account($account_id)
    {
        $account = $this->get_account_by_id($account_id);

        if (null === $account) {
            return $this;
        }

        $account->get_authorization()->remove_token();

        unset($this->_accounts[$account_id]);

        $this->save();

        return $this;
    }

    /**
     * Function run once when upgrading from versions not supporting multiple accounts.
     */
    public static function upgrade_from_single()
    {
        require_once ABSPATH.'wp-includes/pluggable.php';

        // Update Events database, add account_id column
        Events::install_database();

        // Process per blog
        $blog_id = get_current_blog_id();
        if (Core::is_network_authorized()) {
            $token_path = USEYOURDRIVE_CACHEDIR.'/network.access_token';
            $token_name = 'network.access_token';
        } else {
            $token_path = USEYOURDRIVE_CACHEDIR."/{$blog_id}.access_token";
            $token_name = "{$blog_id}.access_token";
        }

        if (false === file_exists($token_path)) {
            // Blog doesn't have an active authorization
            return;
        }

        // Create account with temporarily data
        $account = new Account($blog_id, '', $blog_id);
        $account->get_authorization()->set_token_name($token_name);
        App::set_current_account($account);

        // Load Client for this account
        try {
            App::instance()->start_sdk_client($account);
        } catch (\Exception $ex) {
            @unlink($token_path);

            return;
        }

        // Get & Update User Information
        try {
            $account_data = API::get_account_info();
        } catch (\Exception $ex) {
            @unlink($token_path);

            return;
        }

        // Remove old token file
        @unlink($token_path);
        $account->get_authorization()->remove_token();
        App::clear_current_account();

        // Update all Manually linked folders
        $users = get_users(['fields' => ['ID'], 'blog_id' => $blog_id]);

        // Manually linked folders for users
        foreach ($users as $user) {
            $manually_linked_data = get_user_option('use_your_drive_linkedto', $user->ID);

            if (false === $manually_linked_data) {
                continue;
            }

            $manually_linked_data['accountid'] = $account_data->getId();
            update_user_option($user->ID, 'use_your_drive_linkedto', $manually_linked_data, false);
        }

        // Manually linked folder for guests (currently stored on network level)
        $manually_linked_guests_data = get_site_option('use_your_drive_guestlinkedto');
        if (false !== $manually_linked_guests_data) {
            $manually_linked_guests_data['accountid'] = $account_data->getId();
            update_site_option('use_your_drive_guestlinkedto', $manually_linked_guests_data);
        }

        Processor::reset_complete_cache();
    }

    public function save()
    {
        if (Core::is_network_authorized()) {
            Settings::save_for_network('accounts', $this->_accounts);
        } else {
            Settings::save('accounts', $this->_accounts);
        }
    }

    public static function revoke_authorizations()
    {
        require_once ABSPATH.'wp-admin/includes/class-wp-filesystem-base.php';

        require_once ABSPATH.'wp-admin/includes/class-wp-filesystem-direct.php';

        $wp_file_system = new \WP_Filesystem_Direct(false);

        foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator(USEYOURDRIVE_CACHEDIR, \FilesystemIterator::SKIP_DOTS), \RecursiveIteratorIterator::CHILD_FIRST) as $path) {
            if ('.htaccess' === $path->getFilename()) {
                continue;
            }

            try {
                $wp_file_system->delete($path->getPathname(), true);
            } catch (\Exception $ex) {
                continue;
            }
        }

        Processor::reset_complete_cache();
    }

    private function _init_accounts()
    {
        $this->_accounts = Settings::get('accounts', []);
    }
}
