<?php

namespace StaticDeploy;

use GuzzleHttp\Psr7\Utils as Psr7Utils;

/*
    Singleton instance to allow instantiating once and allow reading
    static properties throughout plugin
*/
class SiteInfo {

    private static ?SiteInfo $instance = null;

    /**
     * Site info.
     *
     * @var mixed[]
     */
    private static $info = [];

    /**
     * Set site info using trailingslashed paths/URLs.
     *
     * @see https://codex.wordpress.org/Determining_Plugin_and_Content_Directories
     */
    public function __construct() {
        $upload_path_and_url = wp_upload_dir();
        $site_url = trailingslashit( site_url() );

        // properties which should not change during plugin execution
        self::$info = apply_filters(
            'static_deploy_siteinfo',
            [
                // Core
                'site_path' => ABSPATH,
                'site_url' => $site_url,

                /*
                    Note:  'home_path' => get_home_path(),
                    // errors trying to find it in StaticDeploy\get_home_path()...
                */
                'home_url' => trailingslashit( get_home_url() ),
                'includes_path' => trailingslashit( ABSPATH . WPINC ),
                'includes_url' => includes_url(),

                /*
                    Q on subdir:
                        Does it matter?
                    'subdirectory' => $this->isSiteInstalledInSubDirectory(),
                        A: It shouldn't, but current mechanism for rewriting URLs
                    has some cases that require knowledge of it...
                */

                // Content
                'content_path' => trailingslashit( WP_CONTENT_DIR ),
                'content_url' => trailingslashit( content_url() ),
                'uploads_path' =>
                    trailingslashit( $upload_path_and_url['basedir'] ),
                'uploads_url' => trailingslashit( $upload_path_and_url['baseurl'] ),

                // Plugins
                'plugins_path' => trailingslashit( WP_PLUGIN_DIR ),
                'plugins_url' => trailingslashit( plugins_url() ),

                // Themes
                'themes_root_path' => trailingslashit( get_theme_root() ),
                'themes_root_url' => trailingslashit( get_theme_root_uri() ),
                'parent_theme_path' => trailingslashit( get_template_directory() ),
                'parent_theme_url' =>
                    trailingslashit( get_template_directory_uri() ),
                'child_theme_path' => trailingslashit( get_stylesheet_directory() ),
                'child_theme_url' =>
                    trailingslashit( get_stylesheet_directory_uri() ),
            ]
        );
    }

    /**
     * Get Path via name
     *
     * @throws StaticDeployException
     */
    public static function getPath( string $name ): string {
        if ( ! self::$instance instanceof SiteInfo ) {
            self::$instance = new SiteInfo();
        }

        // TODO: Move trailingslashit() here ???
        $key = $name . '_path';

        if ( ! array_key_exists( $key, self::$info ) ) {
            $err = 'Attempted to access missing SiteInfo path';
            throw WsLog::ex( esc_html( $err ) );
        }

        /**
         * @var string $original_path
         */
        $original_path = self::$info[ $key ];

        // Standardise all paths to use / (Windows support)
        $standardised_path = str_replace( '\\', '/', $original_path );

        return $standardised_path;
    }

    /**
     * Get URL via name
     *
     * @throws StaticDeployException
     */
    public static function getUrl( string $name ): string {
        if ( ! self::$instance instanceof SiteInfo ) {
            self::$instance = new SiteInfo();
        }

        $key = $name . '_url';

        if ( ! array_key_exists( $key, self::$info ) ) {
            $err = 'Attempted to access missing SiteInfo URL';
            throw WsLog::ex( esc_html( $err ) );
        }

        /**
         * @var string $url
         */
        $url = self::$info[ $key ];

        return $url;
    }

    // TODO Use WP_Http 'curl_enabled' => $this->hasCurlSupport(),
    // didn't see the method vailable in WP_Http
    public static function hasCURLSupport(): bool {
        if ( ! self::$instance instanceof SiteInfo ) {
            self::$instance = new SiteInfo();
        }

        return extension_loaded( 'curl' );
    }

    public static function isUploadsWritable(): bool {
        if ( ! self::$instance instanceof SiteInfo ) {
            self::$instance = new SiteInfo();
        }

        /**
         * @var string $uploads_dir
         */
        $uploads_dir = self::$info['uploads_path'];

        return file_exists( $uploads_dir ) && FilesHelper::isWriteable( $uploads_dir );
    }

    public static function permalinksAreCompatible(): bool {
        if ( ! self::$instance instanceof SiteInfo ) {
            self::$instance = new SiteInfo();
        }

        /**
         * @var string $structure
         */
        $structure = get_option( 'permalink_structure' );

        return strlen( $structure ) && 0 === strcmp( $structure[-1], '/' );
    }

    public static function getPermalinks(): string {
        if ( ! self::$instance instanceof SiteInfo ) {
            self::$instance = new SiteInfo();
        }

        /**
         * @var string $permalink_structure
         */
        $permalink_structure = get_option( 'permalink_structure' );

        return $permalink_structure;
    }

    /**
     * Get Site URL host
     *
     * @throws StaticDeployException
     */
    public static function getSiteURLHost(): string {
        if ( ! self::$instance instanceof SiteInfo ) {
            self::$instance = new SiteInfo();
        }

        /**
         * @var string $site_url
         */
        $site_url = self::$info['site_url'];

        $url_host = Psr7Utils::uriFor( $site_url )->getHost();

        if ( $url_host === '' ) {
            $err = 'Failed to get hostname from Site URL';
            throw WsLog::ex( esc_html( $err ) );
        }

        return $url_host;
    }

    /**
     *  Get all WP site info
     *
     *  @return mixed[]
     */
    public static function getAllInfo(): array {
        if ( ! self::$instance instanceof SiteInfo ) {
            self::$instance = new SiteInfo();
        }

        return self::$info;
    }
}
