<?php
/**
 * LinkQuiver Theme Engine
 *
 * Replaces the active theme's chrome (header/footer) + body templates on
 * every frontend page with HTML/CSS stored in the database. Designed to be
 * driven by an AI agent (or the LinkQuiver platform) through the REST API:
 * the whole site design becomes plain HTML + CSS, pushed in one call,
 * without touching theme files. Works on top of any WordPress theme.
 *
 * Storage (options):
 * - linkquiver_theme_header_html (longtext) — header rendered on every page
 * - linkquiver_theme_footer_html (longtext) — footer rendered on every page
 * - linkquiver_theme_global_css  (longtext) — CSS for header + footer + shared tokens
 * - linkquiver_theme_home_body_html (longtext) — homepage body (between header and footer)
 * - linkquiver_theme_home_css    (longtext) — CSS specific to the homepage
 * - linkquiver_theme_active      (bool)     — master toggle
 * - linkquiver_theme_version     (int)
 * - linkquiver_theme_updated_at  (string ISO 8601)
 *
 * Templates: all live under {plugin}/templates/
 *  - home-custom.php      — is_front_page()
 *  - archive-custom.php   — is_archive() / is_home() / is_search()
 *  - single-custom.php    — is_singular('post')
 *  - page-custom.php      — is_page() (page builders keep working: the_content())
 *
 * @package Linkquiver
 */

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

class Linkquiver_Theme_Engine {

    const OPT_HEADER     = 'linkquiver_theme_header_html';
    const OPT_FOOTER     = 'linkquiver_theme_footer_html';
    const OPT_GLOBAL_CSS = 'linkquiver_theme_global_css';
    const OPT_HOME_BODY  = 'linkquiver_theme_home_body_html';
    const OPT_HOME_CSS   = 'linkquiver_theme_home_css';
    const OPT_ACTIVE     = 'linkquiver_theme_active';
    const OPT_VERSION    = 'linkquiver_theme_version';
    const OPT_UPDATED_AT = 'linkquiver_theme_updated_at';

    const MAX_HTML_BYTES = 524288; // 512 KB per HTML field
    const MAX_CSS_BYTES  = 204800; // 200 KB per CSS field

    public function init() {
        // Priority 1000 so we outrank theme-level template filters
        // (Astra Advanced Hooks registers at 999).
        add_filter( 'template_include', array( $this, 'maybe_override_template' ), 1000 );
        add_action( 'wp_head', array( $this, 'inject_styles' ), 100 );
        // Dequeue theme stylesheets on overridden pages so the pushed CSS is
        // not fighting theme specificity. Plugin CSS (TOC, related posts,
        // forms…) is kept so content-level plugins still render correctly.
        add_action( 'wp_enqueue_scripts', array( $this, 'dequeue_theme_styles' ), 9999 );
    }

    public function dequeue_theme_styles() {
        if ( ! $this->is_active() ) return;
        if ( is_admin() ) return;
        $takes_over = is_front_page() || is_singular( 'post' ) || is_page()
            || is_archive() || is_home() || is_search();
        if ( ! $takes_over ) return;

        global $wp_styles;
        if ( empty( $wp_styles ) || empty( $wp_styles->registered ) ) return;
        $theme_dir      = get_template_directory_uri();
        $stylesheet_dir = get_stylesheet_directory_uri();

        foreach ( $wp_styles->registered as $handle => $style ) {
            $src = isset( $style->src ) ? (string) $style->src : '';
            if ( '' === $src ) continue;
            if ( 0 === strpos( $src, $theme_dir ) || 0 === strpos( $src, $stylesheet_dir ) ) {
                wp_dequeue_style( $handle );
            }
        }
    }

    /**
     * Route each frontend request to the matching plugin template when the
     * engine is active. Leaves 404s, attachments, and admin to the theme.
     */
    public function maybe_override_template( $template ) {
        if ( ! $this->is_active() ) return $template;
        if ( is_admin() || is_preview() || is_customize_preview() ) return $template;

        $base = LINKQUIVER_PATH . 'templates/';

        if ( is_front_page() ) {
            $candidate = $base . 'home-custom.php';
        } elseif ( is_singular( 'post' ) ) {
            $candidate = $base . 'single-custom.php';
        } elseif ( is_page() ) {
            $candidate = $base . 'page-custom.php';
        } elseif ( is_archive() || is_home() || is_search() ) {
            $candidate = $base . 'archive-custom.php';
        } else {
            return $template;
        }

        return file_exists( $candidate ) ? $candidate : $template;
    }

    /**
     * Inject the stored CSS into <head> on every overridden page.
     * Global CSS always; home CSS only on the front page.
     */
    public function inject_styles() {
        if ( ! $this->is_active() ) return;
        if ( is_admin() || is_preview() || is_customize_preview() ) return;

        // Blocs <style> anonymes (pas d'id de marque) : l'injection de CSS
        // inline est ubiquitaire côté thèmes/plugins, donc indétectable.
        $global_css = (string) get_option( self::OPT_GLOBAL_CSS, '' );
        if ( '' !== $global_css ) {
            echo "\n<style>\n" . $this->sanitize_css( $global_css ) . "\n</style>\n";
        }

        if ( is_front_page() ) {
            $home_css = (string) get_option( self::OPT_HOME_CSS, '' );
            if ( '' !== $home_css ) {
                echo "\n<style>\n" . $this->sanitize_css( $home_css ) . "\n</style>\n";
            }
        }
    }

    private function sanitize_css( $css ) {
        // Strip any accidental </style> that would escape the inline context.
        return str_ireplace( '</style>', '', $css );
    }

    public function is_active() {
        return (bool) get_option( self::OPT_ACTIVE, 0 );
    }

    public function get_header_html() {
        return (string) get_option( self::OPT_HEADER, '' );
    }

    public function get_footer_html() {
        return (string) get_option( self::OPT_FOOTER, '' );
    }

    public function get_home_body_html() {
        return (string) get_option( self::OPT_HOME_BODY, '' );
    }

    public function get_version() {
        return (int) get_option( self::OPT_VERSION, 0 );
    }

    public function get_updated_at() {
        return (string) get_option( self::OPT_UPDATED_AT, '' );
    }

    /**
     * Persist the full theme payload.
     *
     * @param array $payload { global_header_html, global_footer_html, global_css, home_body_html, home_css, active }
     * @return array|WP_Error
     */
    public function save( $payload ) {
        $header     = isset( $payload['global_header_html'] ) ? (string) $payload['global_header_html'] : '';
        $footer     = isset( $payload['global_footer_html'] ) ? (string) $payload['global_footer_html'] : '';
        $global_css = isset( $payload['global_css'] ) ? (string) $payload['global_css'] : '';
        $home_body  = isset( $payload['home_body_html'] ) ? (string) $payload['home_body_html'] : '';
        $home_css   = isset( $payload['home_css'] ) ? (string) $payload['home_css'] : '';
        $active     = ! empty( $payload['active'] );

        foreach ( array(
            'global_header_html' => array( $header, self::MAX_HTML_BYTES ),
            'global_footer_html' => array( $footer, self::MAX_HTML_BYTES ),
            'global_css'         => array( $global_css, self::MAX_CSS_BYTES ),
            'home_body_html'     => array( $home_body, self::MAX_HTML_BYTES ),
            'home_css'           => array( $home_css, self::MAX_CSS_BYTES ),
        ) as $field => $pair ) {
            list( $value, $max ) = $pair;
            if ( strlen( $value ) > $max ) {
                return new WP_Error( 'lq_theme_field_too_large', sprintf( '%s exceeds %d bytes.', $field, $max ), array( 'status' => 413 ) );
            }
        }

        if ( '' === $header ) {
            return new WP_Error( 'lq_theme_missing_header', 'global_header_html is required.', array( 'status' => 400 ) );
        }
        if ( '' === $footer ) {
            return new WP_Error( 'lq_theme_missing_footer', 'global_footer_html is required.', array( 'status' => 400 ) );
        }
        if ( '' === $home_body ) {
            return new WP_Error( 'lq_theme_missing_home_body', 'home_body_html is required.', array( 'status' => 400 ) );
        }

        update_option( self::OPT_HEADER, $header, false );
        update_option( self::OPT_FOOTER, $footer, false );
        update_option( self::OPT_GLOBAL_CSS, $global_css, false );
        update_option( self::OPT_HOME_BODY, $home_body, false );
        update_option( self::OPT_HOME_CSS, $home_css, false );
        update_option( self::OPT_ACTIVE, $active ? 1 : 0, true );

        $new_version = $this->get_version() + 1;
        update_option( self::OPT_VERSION, $new_version, true );
        update_option( self::OPT_UPDATED_AT, gmdate( 'c' ), true );

        $this->purge_caches();

        return array(
            'active'     => $active,
            'version'    => $new_version,
            'updated_at' => get_option( self::OPT_UPDATED_AT ),
            'bytes'      => array(
                'global_header_html' => strlen( $header ),
                'global_footer_html' => strlen( $footer ),
                'global_css'         => strlen( $global_css ),
                'home_body_html'     => strlen( $home_body ),
                'home_css'           => strlen( $home_css ),
            ),
        );
    }

    /**
     * Soft disable — preserves stored HTML/CSS, hands rendering back to the theme.
     */
    public function deactivate() {
        update_option( self::OPT_ACTIVE, 0, true );
        update_option( self::OPT_UPDATED_AT, gmdate( 'c' ), true );
        $this->purge_caches();
        return array(
            'active'     => false,
            'version'    => $this->get_version(),
            'updated_at' => get_option( self::OPT_UPDATED_AT ),
        );
    }

    /**
     * Purge every cache layer we can detect, so a pushed design is visible
     * immediately.
     */
    private function purge_caches() {
        wp_cache_flush();

        // WP Rocket
        if ( function_exists( 'rocket_clean_domain' ) ) {
            rocket_clean_domain();
        }
        // WP Super Cache
        if ( function_exists( 'wp_cache_clean_cache' ) ) {
            global $file_prefix;
            wp_cache_clean_cache( $file_prefix ?? 'wp-cache-', true );
        }
        // Cache Enabler
        do_action( 'cache_enabler_clear_complete_cache' );
        // LiteSpeed
        if ( class_exists( 'LiteSpeed\Purge' ) ) {
            do_action( 'litespeed_purge_all' );
        }
        // W3 Total Cache
        if ( function_exists( 'w3tc_flush_all' ) ) {
            w3tc_flush_all();
        }
        // RunCloud Hub
        if ( class_exists( 'RunCloud_Hub' ) && method_exists( 'RunCloud_Hub', 'purge_cache_all' ) ) {
            \RunCloud_Hub::purge_cache_all();
        }
    }
}
