<?php
/**
 * Font Registry for Maple Local Fonts.
 *
 * @package Maple_Local_Fonts
 */

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

/**
 * Class MLF_Font_Registry
 *
 * Handles registering fonts with WordPress Font Library API.
 */
class MLF_Font_Registry {

    /**
     * Register a font family with WordPress Font Library.
     *
     * @param string $font_name Display name (e.g., "Open Sans").
     * @param string $font_slug Slug (e.g., "open-sans").
     * @param array  $files     Array of downloaded file data.
     * @return int|WP_Error Font family post ID or error.
     */
    public function register_font($font_name, $font_slug, $files) {
        // Check if font already exists
        $existing = get_posts([
            'post_type'      => 'wp_font_family',
            'name'           => $font_slug,
            'posts_per_page' => 1,
            'post_status'    => 'publish',
        ]);

        if (!empty($existing)) {
            return new WP_Error('font_exists', 'Font family already installed');
        }

        // Get font directory
        $font_dir = wp_get_font_dir();

        // Build font face array for WordPress
        $font_faces = [];
        foreach ($files as $file) {
            $filename = basename($file['path']);
            $font_faces[] = [
                'fontFamily' => $font_name,
                'fontWeight' => $file['weight'],
                'fontStyle'  => $file['style'],
                'src'        => 'file:./' . $filename,
            ];
        }

        // Build font family settings
        $font_family_settings = [
            'name'       => $font_name,
            'slug'       => $font_slug,
            'fontFamily' => sprintf('"%s", sans-serif', $font_name),
            'fontFace'   => $font_faces,
        ];

        // Create font family post
        $family_id = wp_insert_post([
            'post_type'    => 'wp_font_family',
            'post_title'   => $font_name,
            'post_name'    => $font_slug,
            'post_status'  => 'publish',
            'post_content' => wp_json_encode($font_family_settings),
        ]);

        if (is_wp_error($family_id)) {
            return $family_id;
        }

        // Mark as imported by our plugin (for identification)
        update_post_meta($family_id, '_mlf_imported', '1');
        update_post_meta($family_id, '_mlf_import_date', current_time('mysql'));

        // Create font face posts (children)
        foreach ($files as $file) {
            $filename = basename($file['path']);

            $face_settings = [
                'fontFamily' => $font_name,
                'fontWeight' => $file['weight'],
                'fontStyle'  => $file['style'],
                'src'        => 'file:./' . $filename,
            ];

            wp_insert_post([
                'post_type'    => 'wp_font_face',
                'post_parent'  => $family_id,
                'post_title'   => sprintf('%s %s %s', $font_name, $file['weight'], $file['style']),
                'post_status'  => 'publish',
                'post_content' => wp_json_encode($face_settings),
            ]);
        }

        // Clear font caches
        delete_transient('wp_font_library_fonts');
        delete_transient('mlf_imported_fonts_list');

        return $family_id;
    }

    /**
     * Delete a font family and its files.
     *
     * @param int $family_id Font family post ID.
     * @return bool|WP_Error True on success, error on failure.
     */
    public function delete_font($family_id) {
        $family = get_post($family_id);

        if (!$family || $family->post_type !== 'wp_font_family') {
            return new WP_Error('not_found', 'Font family not found');
        }

        // Verify it's one we imported
        if (get_post_meta($family_id, '_mlf_imported', true) !== '1') {
            return new WP_Error('not_ours', 'Cannot delete fonts not imported by this plugin');
        }

        // Get font faces (children)
        $faces = get_children([
            'post_parent' => $family_id,
            'post_type'   => 'wp_font_face',
        ]);

        $font_dir = wp_get_font_dir();

        // Delete font face files and posts
        foreach ($faces as $face) {
            $settings = json_decode($face->post_content, true);

            if (isset($settings['src'])) {
                // Convert file:. URL to path
                $src = $settings['src'];
                $src = str_replace('file:./', '', $src);
                $file_path = trailingslashit($font_dir['path']) . basename($src);

                // Validate path and extension before deletion
                if ($this->validate_font_path($file_path)
                    && pathinfo($file_path, PATHINFO_EXTENSION) === 'woff2'
                    && file_exists($file_path)) {
                    wp_delete_file($file_path);
                }
            }

            wp_delete_post($face->ID, true);
        }

        // Delete family post
        wp_delete_post($family_id, true);

        // Clear caches
        delete_transient('wp_font_library_fonts');
        delete_transient('mlf_imported_fonts_list');

        return true;
    }

    /**
     * Get all fonts imported by this plugin.
     *
     * Uses optimized queries to avoid N+1 pattern.
     *
     * @return array Array of font data.
     */
    public function get_imported_fonts() {
        // Check transient cache first
        $cached = get_transient('mlf_imported_fonts_list');
        if ($cached !== false) {
            return $cached;
        }

        $fonts = get_posts([
            'post_type'      => 'wp_font_family',
            'posts_per_page' => 100,
            'post_status'    => 'publish',
            'meta_key'       => '_mlf_imported',
            'meta_value'     => '1',
        ]);

        if (empty($fonts)) {
            set_transient('mlf_imported_fonts_list', [], 5 * MINUTE_IN_SECONDS);
            return [];
        }

        // Collect all font IDs for batch query
        $font_ids = wp_list_pluck($fonts, 'ID');

        // Single query to get ALL font faces for ALL fonts (fixes N+1)
        $all_faces = get_posts([
            'post_type'      => 'wp_font_face',
            'posts_per_page' => 1000, // Max 100 fonts × 9 weights × 2 styles = 1800, but limit reasonably
            'post_status'    => 'publish',
            'post_parent__in' => $font_ids,
        ]);

        // Group faces by parent font ID
        $faces_by_font = [];
        foreach ($all_faces as $face) {
            $parent_id = $face->post_parent;
            if (!isset($faces_by_font[$parent_id])) {
                $faces_by_font[$parent_id] = [];
            }
            $faces_by_font[$parent_id][] = $face;
        }

        // Batch get all import dates in single query
        $import_dates = [];
        foreach ($font_ids as $font_id) {
            $import_dates[$font_id] = get_post_meta($font_id, '_mlf_import_date', true);
        }

        $result = [];

        foreach ($fonts as $font) {
            $settings = json_decode($font->post_content, true);

            // Get variants from pre-fetched data
            $faces = $faces_by_font[$font->ID] ?? [];

            $variants = [];
            foreach ($faces as $face) {
                $face_settings = json_decode($face->post_content, true);
                $variants[] = [
                    'weight' => $face_settings['fontWeight'] ?? '400',
                    'style'  => $face_settings['fontStyle'] ?? 'normal',
                ];
            }

            // Sort variants by weight then style
            usort($variants, function($a, $b) {
                $weight_cmp = intval($a['weight']) - intval($b['weight']);
                if ($weight_cmp !== 0) {
                    return $weight_cmp;
                }
                return strcmp($a['style'], $b['style']);
            });

            $result[] = [
                'id'          => $font->ID,
                'name'        => $settings['name'] ?? $font->post_title,
                'slug'        => $settings['slug'] ?? $font->post_name,
                'variants'    => $variants,
                'import_date' => $import_dates[$font->ID] ?? '',
            ];
        }

        // Cache for 5 minutes
        set_transient('mlf_imported_fonts_list', $result, 5 * MINUTE_IN_SECONDS);

        return $result;
    }

    /**
     * Validate that a path is within the WordPress fonts directory.
     *
     * @param string $path Full path to validate.
     * @return bool True if path is safe, false otherwise.
     */
    private function validate_font_path($path) {
        $font_dir = wp_get_font_dir();
        $fonts_path = wp_normalize_path(trailingslashit($font_dir['path']));

        // Resolve to real path (handles ../ etc)
        $real_path = realpath($path);

        // If realpath fails, file doesn't exist yet - validate the directory
        if ($real_path === false) {
            $dir = dirname($path);
            $real_dir = realpath($dir);
            if ($real_dir === false) {
                return false;
            }
            $real_path = wp_normalize_path($real_dir . '/' . basename($path));
        } else {
            $real_path = wp_normalize_path($real_path);
        }

        // Must be within fonts directory
        return strpos($real_path, $fonts_path) === 0;
    }
}
