<?php
/**
 * Font Server for Maple Local Fonts.
 *
 * Serves font files and CSS through PHP with proper headers.
 * This ensures CORS and MIME types work regardless of server configuration.
 *
 * @package Maple_Local_Fonts
 */

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

/**
 * Class MLF_Font_Server
 *
 * Handles serving font files and CSS with proper headers via REST API.
 */
class MLF_Font_Server {

    /**
     * Register REST API routes.
     */
    public function register_routes() {
        // Serve individual font files
        register_rest_route('mlf/v1', '/font/(?P<filename>[a-zA-Z0-9_\-]+\.woff2)', [
            'methods'             => 'GET',
            'callback'            => [$this, 'serve_font'],
            'permission_callback' => '__return_true',
            'args'                => [
                'filename' => [
                    'required'          => true,
                    'validate_callback' => [$this, 'validate_filename'],
                ],
            ],
        ]);

        // Serve CSS file (like Google Fonts does)
        register_rest_route('mlf/v1', '/css', [
            'methods'             => 'GET',
            'callback'            => [$this, 'serve_css'],
            'permission_callback' => '__return_true',
        ]);
    }

    /**
     * Validate font filename.
     *
     * @param string $filename The filename to validate.
     * @return bool True if valid.
     */
    public function validate_filename($filename) {
        // Only allow alphanumeric, underscore, hyphen, and .woff2 extension
        if (!preg_match('/^[a-zA-Z0-9_\-]+\.woff2$/', $filename)) {
            return false;
        }

        // Prevent directory traversal
        if (strpos($filename, '..') !== false || strpos($filename, '/') !== false) {
            return false;
        }

        return true;
    }

    /**
     * Serve a font file with proper headers.
     *
     * @param WP_REST_Request $request The request object.
     * @return WP_REST_Response|WP_Error Response or error.
     */
    public function serve_font($request) {
        $filename = $request->get_param('filename');

        // Get font directory
        $font_dir = wp_get_font_dir();
        $file_path = trailingslashit($font_dir['path']) . $filename;

        // Validate file exists and is within fonts directory
        $real_path = realpath($file_path);
        $fonts_path = realpath($font_dir['path']);

        if (!$real_path || !$fonts_path || strpos($real_path, $fonts_path) !== 0) {
            return new WP_Error('not_found', 'Font not found', ['status' => 404]);
        }

        if (!file_exists($real_path)) {
            return new WP_Error('not_found', 'Font not found', ['status' => 404]);
        }

        // Verify it's a woff2 file
        if (pathinfo($real_path, PATHINFO_EXTENSION) !== 'woff2') {
            return new WP_Error('invalid_type', 'Invalid file type', ['status' => 400]);
        }

        // Read file content
        $content = file_get_contents($real_path);

        if ($content === false) {
            return new WP_Error('read_error', 'Could not read font file', ['status' => 500]);
        }

        // Verify WOFF2 magic bytes
        if (substr($content, 0, 4) !== 'wOF2') {
            return new WP_Error('invalid_format', 'Invalid font format', ['status' => 400]);
        }

        // Send font with proper headers
        $response = new WP_REST_Response($content);
        $response->set_status(200);
        $response->set_headers([
            'Content-Type'                  => 'font/woff2',
            'Content-Length'                => strlen($content),
            'Access-Control-Allow-Origin'   => '*',
            'Access-Control-Allow-Methods'  => 'GET, OPTIONS',
            'Cross-Origin-Resource-Policy'  => 'cross-origin',
            'Cache-Control'                 => 'public, max-age=31536000, immutable',
            'Vary'                          => 'Accept-Encoding',
        ]);

        return $response;
    }

    /**
     * Serve CSS file with @font-face rules (mimics Google Fonts).
     *
     * @param WP_REST_Request $request The request object.
     * @return WP_REST_Response Response with CSS content.
     */
    public function serve_css($request) {
        $registry = new MLF_Font_Registry();
        $fonts = $registry->get_imported_fonts();

        if (empty($fonts)) {
            $response = new WP_REST_Response('/* No fonts installed */');
            $response->set_headers(['Content-Type' => 'text/css; charset=UTF-8']);
            return $response;
        }

        $css = "/* Maple Local Fonts - Generated CSS */\n\n";

        foreach ($fonts as $font) {
            $font_slug = sanitize_title($font['name']);

            foreach ($font['variants'] as $variant) {
                $weight = $variant['weight'];
                $style = $variant['style'];

                // Build filename
                if (strpos($weight, ' ') !== false) {
                    $filename = sprintf('%s_%s_variable.woff2', $font_slug, $style);
                } else {
                    $filename = sprintf('%s_%s_%s.woff2', $font_slug, $style, $weight);
                }

                // Use REST API URL for font file
                $font_url = rest_url('mlf/v1/font/' . $filename);

                // Generate @font-face rule (format like Google Fonts)
                $css .= "/* {$style} {$weight} */\n";
                $css .= "@font-face {\n";
                $css .= "  font-family: '{$font['name']}';\n";
                $css .= "  font-style: {$style};\n";
                $css .= "  font-weight: {$weight};\n";
                $css .= "  font-display: swap;\n";
                $css .= "  src: url({$font_url}) format('woff2');\n";
                $css .= "}\n\n";
            }
        }

        $response = new WP_REST_Response($css);
        $response->set_status(200);
        $response->set_headers([
            'Content-Type'                => 'text/css; charset=UTF-8',
            'Access-Control-Allow-Origin' => '*',
            'Cache-Control'               => 'public, max-age=86400',
        ]);

        return $response;
    }
}
