<?php

/**
 * Prompt template manager
 *
 * @package SlideMind
 * @since 2.0.0
 */
namespace SlideMind\Core;

if ( !defined( 'ABSPATH' ) ) {
    exit;
}
class TemplateManager {
    /**
     * Configuration repository
     * @var ConfigRepository
     */
    private $config_repository;

    /**
     * Post type
     * @var string
     */
    private $post_type = 'slidemind_config';

    /**
     * Meta keys prefix
     * @var string
     */
    private $meta_prefix = '_slidemind_';

    /**
     * Constructor
     *
     * @param ConfigRepository $config_repository
     */
    public function __construct( ConfigRepository $config_repository ) {
        $this->config_repository = $config_repository;
    }

    /**
     * Retrieves all templates
     *
     * @return array
     */
    public function get_all() {
        $args = [
            'post_type'      => $this->post_type,
            'post_status'    => 'any',
            'posts_per_page' => -1,
            'orderby'        => 'title',
            'order'          => 'ASC',
            'meta_query'     => [[
                'key'     => $this->meta_prefix . 'config_type',
                'value'   => 'template',
                'compare' => '=',
            ]],
        ];
        $posts = get_posts( $args );
        $templates = [];
        foreach ( $posts as $post ) {
            $templates[] = $this->format_template( $post );
        }
        return $templates;
    }

    /**
     * Retrieves a template by its ID
     *
     * @param int $post_id
     * @return array|null
     */
    public function get_by_id( $post_id ) {
        $post = get_post( $post_id );
        if ( !$post || $post->post_type !== $this->post_type ) {
            return null;
        }
        $type = get_post_meta( $post_id, $this->meta_prefix . 'config_type', true );
        if ( $type !== 'template' ) {
            return null;
        }
        return $this->format_template( $post );
    }

    /**
     * Retrieves a template by its slug
     *
     * @param string $slug
     * @return array|null
     */
    public function get_by_slug( $slug ) {
        $args = [
            'post_type'      => $this->post_type,
            'post_status'    => 'any',
            'posts_per_page' => 1,
            'meta_query'     => [
                'relation' => 'AND',
                [
                    'key'     => $this->meta_prefix . 'config_type',
                    'value'   => 'template',
                    'compare' => '=',
                ],
                [
                    'key'     => $this->meta_prefix . 'template_slug',
                    'value'   => sanitize_text_field( $slug ),
                    'compare' => '=',
                ],
            ],
        ];
        $posts = get_posts( $args );
        if ( empty( $posts ) ) {
            return null;
        }
        return $this->format_template( $posts[0] );
    }

    /**
     * Creates a new template
     *
     * @param array $data
     * @return int|\WP_Error
     */
    public function create( $data ) {
        if ( empty( $data['title'] ) ) {
            return new \WP_Error('missing_title', __( 'The title is required', 'slidemind' ));
        }
        // Generate a slug if not provided
        if ( empty( $data['slug'] ) ) {
            $data['slug'] = sanitize_title( $data['title'] );
        }
        // Ensure slug uniqueness
        $data['slug'] = $this->ensure_unique_slug( $data['slug'] );
        $post_data = [
            'post_type'   => $this->post_type,
            'post_status' => ( isset( $data['status'] ) ? $data['status'] : 'publish' ),
            'post_title'  => sanitize_text_field( $data['title'] ),
        ];
        $post_id = wp_insert_post( $post_data, true );
        if ( is_wp_error( $post_id ) ) {
            return $post_id;
        }
        // Mark as template
        update_post_meta( $post_id, $this->meta_prefix . 'config_type', 'template' );
        // Save meta
        $this->save_template_meta( $post_id, $data );
        return $post_id;
    }

    /**
     * Updates a template
     *
     * @param int $post_id
     * @param array $data
     * @return bool|\WP_Error
     */
    public function update( $post_id, $data ) {
        $template = $this->get_by_id( $post_id );
        if ( !$template ) {
            return new \WP_Error('invalid_template', __( 'Template not found', 'slidemind' ));
        }
        if ( isset( $data['title'] ) ) {
            wp_update_post( [
                'ID'         => $post_id,
                'post_title' => sanitize_text_field( $data['title'] ),
            ] );
        }
        if ( isset( $data['status'] ) ) {
            wp_update_post( [
                'ID'          => $post_id,
                'post_status' => $data['status'],
            ] );
        }
        $this->save_template_meta( $post_id, $data );
        return true;
    }

    /**
     * Deletes a template
     *
     * @param int $post_id
     * @return bool|\WP_Error
     */
    public function delete( $post_id ) {
        $template = $this->get_by_id( $post_id );
        if ( !$template ) {
            return new \WP_Error('invalid_template', __( 'Template not found', 'slidemind' ));
        }
        // Refuse deletion of default templates
        if ( $template['is_default'] ) {
            return new \WP_Error('cannot_delete_default', __( 'Cannot delete a default template', 'slidemind' ));
        }
        $result = wp_delete_post( $post_id, true );
        return $result !== false;
    }

    /**
     * Loads default templates from JSON files
     */
    public function seed_defaults() {
        $templates_dir = SLIDEMIND_PLUGIN_PATH . 'templates/';
        $json_files = glob( $templates_dir . '*.json' );
        if ( empty( $json_files ) ) {
            return;
        }
        foreach ( $json_files as $file ) {
            // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- Local file read
            $json = file_get_contents( $file );
            $data = json_decode( $json, true );
            if ( !$data || empty( $data['slug'] ) ) {
                continue;
            }
            // Check if this template already exists
            $existing = $this->get_by_slug( $data['slug'] );
            if ( $existing ) {
                continue;
            }
            $data = $this->translate_template_data( $data );
            $system_prompt = $this->adapt_prompt_for_plan( $data['system_prompt'] ?? '' );
            // Create the template
            $this->create( [
                'title'            => $data['name'],
                'slug'             => $data['slug'],
                'description'      => $data['description'] ?? '',
                'icon'             => $data['icon'] ?? '',
                'system_prompt'    => $system_prompt,
                'temperature'      => $data['temperature'] ?? 0.7,
                'max_tokens'       => $data['max_tokens'] ?? 1024,
                'variables'        => $data['variables'] ?? [],
                'widget_mode'      => $data['widget_mode'] ?? '',
                'max_turns'        => $data['max_turns'] ?? 0,
                'closing_message'  => $data['closing_message'] ?? '',
                'opening_message'  => $data['opening_message'] ?? '',
                'graceful_close'   => $data['graceful_close'] ?? false,
                'output_variables' => $data['output_variables'] ?? [],
                'is_default'       => true,
                'status'           => 'publish',
            ] );
        }
    }

    /**
     * Replaces premium-only placeholders in a system prompt so seeded templates
     * remain coherent on the free build (no Courses/Modules CPTs).
     *
     * Why: default templates authored for Pro reference {{course_*}} and
     * {{module_*}} vars which resolve to empty strings in free, leaving the
     * prompt with orphan labels like "Course: ". Swapping them for generic
     * phrases keeps the instruction readable and pedagogically usable.
     */
    private function adapt_prompt_for_plan( string $prompt ) : string {
        if ( $prompt === '' ) {
            return $prompt;
        }
        return strtr( $prompt, [
            '{{course_theme}}'      => 'this course',
            '{{course_objectives}}' => 'the course objectives',
            '{{course_content}}'    => 'the course content',
            '{{module_theme}}'      => 'this module',
            '{{module_objectives}}' => 'the module objectives',
            '{{module_content}}'    => 'the module content',
        ] );
    }

    /**
     * Resets a default template from its JSON file
     *
     * @param string $slug
     * @return bool|\WP_Error
     */
    public function reset_default( $slug ) {
        $template = $this->get_by_slug( $slug );
        if ( !$template ) {
            return new \WP_Error('not_found', __( 'Template not found', 'slidemind' ));
        }
        if ( !$template['is_default'] ) {
            return new \WP_Error('not_default', __( 'This template is not a default template', 'slidemind' ));
        }
        // Find the corresponding JSON file
        $templates_dir = SLIDEMIND_PLUGIN_PATH . 'templates/';
        $json_files = glob( $templates_dir . '*.json' );
        foreach ( $json_files as $file ) {
            // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- Local file read
            $json = file_get_contents( $file );
            $data = json_decode( $json, true );
            if ( $data && isset( $data['slug'] ) && $data['slug'] === $slug ) {
                $data = $this->translate_template_data( $data );
                // Reload data from the JSON
                $this->update( $template['id'], [
                    'title'            => $data['name'],
                    'description'      => $data['description'] ?? '',
                    'icon'             => $data['icon'] ?? '',
                    'system_prompt'    => $this->adapt_prompt_for_plan( $data['system_prompt'] ?? '' ),
                    'temperature'      => $data['temperature'] ?? 0.7,
                    'max_tokens'       => $data['max_tokens'] ?? 1024,
                    'variables'        => $data['variables'] ?? [],
                    'widget_mode'      => $data['widget_mode'] ?? '',
                    'max_turns'        => $data['max_turns'] ?? 0,
                    'closing_message'  => $data['closing_message'] ?? '',
                    'opening_message'  => $data['opening_message'] ?? '',
                    'graceful_close'   => $data['graceful_close'] ?? false,
                    'output_variables' => $data['output_variables'] ?? [],
                ] );
                return true;
            }
        }
        return new \WP_Error('file_not_found', __( 'Template JSON file not found', 'slidemind' ));
    }

    /**
     * Translates template data fields from JSON using the current locale.
     *
     * JSON templates are stored in English (source language). This method
     * applies __() to translatable fields so the DB stores the localized
     * version matching the site language.
     *
     * @param array $data Raw template data from JSON.
     * @return array Template data with translated strings.
     */
    private function translate_template_data( array $data ) : array {
        // Template strings are stored in English in JSON files.
        // Translatable strings are extracted to the POT file via
        // templates/template-strings.php (literal calls for the scanner).
        // We no longer call __($variable) here because WP.org translation
        // scanners cannot extract strings from variables. Templates are
        // seeded in English; translations are handled by WordPress i18n at
        // display time when needed.
        return $data;
    }

    /**
     * Exports a template as JSON
     *
     * @param int $post_id
     * @return string|\WP_Error
     */
    public function export( $post_id ) {
        $template = $this->get_by_id( $post_id );
        if ( !$template ) {
            return new \WP_Error('not_found', __( 'Template not found', 'slidemind' ));
        }
        $export = [
            'slidemind_template_version' => '1.1',
            'name'                       => $template['title'],
            'slug'                       => $template['slug'],
            'description'                => $template['description'],
            'icon'                       => $template['icon'],
            'widget_mode'                => $template['widget_mode'],
            'system_prompt'              => $template['system_prompt'],
            'temperature'                => $template['temperature'],
            'max_tokens'                 => $template['max_tokens'],
            'variables'                  => $template['variables'],
        ];
        // Chat-specific fields
        if ( $template['widget_mode'] === 'chat' ) {
            $export['max_turns'] = $template['max_turns'];
            $export['graceful_close'] = $template['graceful_close'];
            $export['closing_message'] = $template['closing_message'];
            $export['opening_message'] = $template['opening_message'];
        }
        // Output variables
        if ( !empty( $template['output_variables'] ) ) {
            $export['output_variables'] = $template['output_variables'];
        }
        return wp_json_encode( $export, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE );
    }

    /**
     * Imports a template from JSON
     *
     * @param string $json
     * @return int|\WP_Error
     */
    public function import( $json ) {
        $data = json_decode( $json, true );
        if ( !$data ) {
            return new \WP_Error('invalid_json', __( 'Invalid JSON', 'slidemind' ));
        }
        if ( empty( $data['name'] ) ) {
            return new \WP_Error('missing_name', __( 'The template name is required', 'slidemind' ));
        }
        // The slug will be automatically suffixed if duplicate via ensure_unique_slug
        $slug = ( !empty( $data['slug'] ) ? $data['slug'] : sanitize_title( $data['name'] ) );
        return $this->create( [
            'title'            => $data['name'],
            'slug'             => $slug,
            'description'      => $data['description'] ?? '',
            'icon'             => $data['icon'] ?? '',
            'system_prompt'    => $data['system_prompt'] ?? '',
            'temperature'      => $data['temperature'] ?? 0.7,
            'max_tokens'       => $data['max_tokens'] ?? 1024,
            'variables'        => $data['variables'] ?? [],
            'widget_mode'      => $data['widget_mode'] ?? '',
            'max_turns'        => $data['max_turns'] ?? 0,
            'closing_message'  => $data['closing_message'] ?? '',
            'opening_message'  => $data['opening_message'] ?? '',
            'graceful_close'   => $data['graceful_close'] ?? false,
            'output_variables' => $data['output_variables'] ?? [],
            'is_default'       => false,
            'status'           => 'publish',
        ] );
    }

    /**
     * Formats a template as a standard array
     *
     * @param \WP_Post $post
     * @return array
     */
    private function format_template( $post ) {
        $variables = get_post_meta( $post->ID, $this->meta_prefix . 'variables', true );
        return [
            'id'               => $post->ID,
            'title'            => $post->post_title,
            'status'           => $post->post_status,
            'config_type'      => 'template',
            'slug'             => get_post_meta( $post->ID, $this->meta_prefix . 'template_slug', true ),
            'description'      => get_post_meta( $post->ID, $this->meta_prefix . 'template_description', true ),
            'icon'             => get_post_meta( $post->ID, $this->meta_prefix . 'template_icon', true ),
            'system_prompt'    => get_post_meta( $post->ID, $this->meta_prefix . 'system_prompt', true ),
            'temperature'      => ( (float) get_post_meta( $post->ID, $this->meta_prefix . 'temperature', true ) ?: 0.7 ),
            'max_tokens'       => ( (int) get_post_meta( $post->ID, $this->meta_prefix . 'max_tokens', true ) ?: 1024 ),
            'variables'        => ( is_array( $variables ) ? $variables : [] ),
            'widget_mode'      => ( get_post_meta( $post->ID, $this->meta_prefix . 'template_widget_mode', true ) ?: '' ),
            'max_turns'        => (int) get_post_meta( $post->ID, $this->meta_prefix . 'template_max_turns', true ),
            'closing_message'  => ( get_post_meta( $post->ID, $this->meta_prefix . 'template_closing_message', true ) ?: '' ),
            'opening_message'  => ( get_post_meta( $post->ID, $this->meta_prefix . 'template_opening_message', true ) ?: '' ),
            'graceful_close'   => (bool) get_post_meta( $post->ID, $this->meta_prefix . 'template_graceful_close', true ),
            'output_variables' => json_decode( ( get_post_meta( $post->ID, $this->meta_prefix . 'template_output_variables', true ) ?: '[]' ), true ),
            'is_default'       => (bool) get_post_meta( $post->ID, $this->meta_prefix . 'is_default', true ),
            'created_at'       => $post->post_date,
            'updated_at'       => $post->post_modified,
        ];
    }

    /**
     * Saves the meta of a template
     *
     * @param int $post_id
     * @param array $data
     */
    private function save_template_meta( $post_id, $data ) {
        if ( isset( $data['slug'] ) ) {
            update_post_meta( $post_id, $this->meta_prefix . 'template_slug', sanitize_text_field( $data['slug'] ) );
        }
        if ( isset( $data['description'] ) ) {
            update_post_meta( $post_id, $this->meta_prefix . 'template_description', sanitize_text_field( $data['description'] ) );
        }
        if ( isset( $data['icon'] ) ) {
            update_post_meta( $post_id, $this->meta_prefix . 'template_icon', sanitize_text_field( $data['icon'] ) );
        }
        if ( isset( $data['system_prompt'] ) ) {
            update_post_meta( $post_id, $this->meta_prefix . 'system_prompt', wp_kses_post( $data['system_prompt'] ) );
        }
        if ( isset( $data['temperature'] ) ) {
            $temp = max( 0, min( 2, (float) $data['temperature'] ) );
            update_post_meta( $post_id, $this->meta_prefix . 'temperature', $temp );
        }
        if ( isset( $data['max_tokens'] ) ) {
            $tokens = max( 1, min( 128000, (int) $data['max_tokens'] ) );
            update_post_meta( $post_id, $this->meta_prefix . 'max_tokens', $tokens );
        }
        if ( isset( $data['variables'] ) && is_array( $data['variables'] ) ) {
            update_post_meta( $post_id, $this->meta_prefix . 'variables', $data['variables'] );
        }
        if ( isset( $data['widget_mode'] ) ) {
            $mode = ( in_array( $data['widget_mode'], ['qa', 'chat'], true ) ? $data['widget_mode'] : '' );
            update_post_meta( $post_id, $this->meta_prefix . 'template_widget_mode', $mode );
        }
        if ( isset( $data['max_turns'] ) ) {
            update_post_meta( $post_id, $this->meta_prefix . 'template_max_turns', max( 0, min( 100, (int) $data['max_turns'] ) ) );
        }
        if ( isset( $data['closing_message'] ) ) {
            update_post_meta( $post_id, $this->meta_prefix . 'template_closing_message', sanitize_textarea_field( $data['closing_message'] ) );
        }
        if ( isset( $data['opening_message'] ) ) {
            update_post_meta( $post_id, $this->meta_prefix . 'template_opening_message', sanitize_textarea_field( $data['opening_message'] ) );
        }
        if ( isset( $data['graceful_close'] ) ) {
            update_post_meta( $post_id, $this->meta_prefix . 'template_graceful_close', ( !empty( $data['graceful_close'] ) ? '1' : '0' ) );
        }
        if ( isset( $data['output_variables'] ) ) {
            $vars = ( is_array( $data['output_variables'] ) ? $data['output_variables'] : [] );
            update_post_meta( $post_id, $this->meta_prefix . 'template_output_variables', wp_json_encode( $vars, JSON_UNESCAPED_UNICODE ) );
        }
        if ( isset( $data['is_default'] ) ) {
            update_post_meta( $post_id, $this->meta_prefix . 'is_default', (bool) $data['is_default'] );
        }
    }

    /**
     * Ensures slug uniqueness
     *
     * @param string $slug
     * @param int $exclude_id ID to exclude from the check
     * @return string
     */
    private function ensure_unique_slug( $slug, $exclude_id = 0 ) {
        $original_slug = $slug;
        $counter = 2;
        while ( $this->slug_exists( $slug, $exclude_id ) ) {
            $slug = $original_slug . '-' . $counter;
            $counter++;
        }
        return $slug;
    }

    /**
     * Checks if a slug already exists
     *
     * @param string $slug
     * @param int $exclude_id
     * @return bool
     */
    private function slug_exists( $slug, $exclude_id = 0 ) {
        $args = [
            'post_type'      => $this->post_type,
            'post_status'    => 'any',
            'posts_per_page' => 1,
            'fields'         => 'ids',
            'meta_query'     => [
                'relation' => 'AND',
                [
                    'key'     => $this->meta_prefix . 'config_type',
                    'value'   => 'template',
                    'compare' => '=',
                ],
                [
                    'key'     => $this->meta_prefix . 'template_slug',
                    'value'   => $slug,
                    'compare' => '=',
                ],
            ],
        ];
        if ( $exclude_id ) {
            $args['post__not_in'] = [$exclude_id];
        }
        return count( get_posts( $args ) ) > 0;
    }

    /**
     * Creates a new custom (non-default) template from a data array.
     *
     * Thin wrapper around create() that forces is_default = false and
     * status = publish, ensuring imported templates land as user-owned.
     *
     * @param array $data
     * @return int|\WP_Error
     */
    public function create_custom( array $data ) {
        $data['is_default'] = false;
        if ( !isset( $data['status'] ) ) {
            $data['status'] = 'publish';
        }
        return $this->create( $data );
    }

    /**
     * Updates an existing custom template identified by slug.
     *
     * Mirrors update() but resolves the post_id from the slug first.
     * Returns WP_Error if the slug is not found or belongs to a default template.
     *
     * @param string $slug
     * @param array  $data
     * @return bool|\WP_Error
     */
    public function update_by_slug( string $slug, array $data ) {
        $template = $this->get_by_slug( $slug );
        if ( !$template ) {
            return new \WP_Error(
                'not_found',
                /* translators: %s: template slug */
                sprintf( __( 'Template "%s" not found', 'slidemind' ), $slug )
            );
        }
        if ( !empty( $template['is_default'] ) ) {
            return new \WP_Error('cannot_overwrite_default', __( 'Cannot overwrite a default template via import', 'slidemind' ));
        }
        return $this->update( (int) $template['id'], $data );
    }

}
