<?php
namespace MODELORA\Api;

use MODELORA\Upload\Manager as UploadManager;

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

class Routes
{
    private function is_debug_enabled(): bool
    {
        $enabled = defined('WP_DEBUG') && WP_DEBUG;
        return (bool) apply_filters('modelora_debug_logs_enabled', $enabled);
    }

    private function build_trace_id(): string
    {
        if (function_exists('wp_generate_uuid4')) {
            return 'modelora-' . wp_generate_uuid4();
        }

        return 'modelora-' . uniqid('', true);
    }

    private function request_trace_id(\WP_REST_Request $request): string
    {
        $raw = (string) $request->get_header('x-modelora-trace');
        $trace_id = preg_replace('/[^a-zA-Z0-9\-_.:]/', '', $raw);

        return ! empty($trace_id) ? $trace_id : $this->build_trace_id();
    }

    private function debug_log(string $stage, array $context = []): void
    {
        if (! $this->is_debug_enabled()) {
            return;
        }

        /**
         * Allow debug logging integrations without hard-coding error_log usage.
         */
        do_action('modelora_debug_log', $stage, $context);
    }

    public function register(): void
    {
        add_action('rest_api_init', [$this, 'register_routes']);
    }

    private function verify_nonce_or_die(\WP_REST_Request $request): void
    {
        $nonce = $request->get_header('X-WP-Nonce');
        if (! $nonce || ! wp_verify_nonce($nonce, 'wp_rest')) {
            wp_die(
                wp_json_encode(['success' => false, 'message' => __('Nonce verification failed.', 'modelora-3d-product-viewer')]),
                'Forbidden',
                ['status' => 403, 'content_type' => 'application/json']
            );
        }
    }

    public function register_routes(): void
    {
        register_rest_route('modelora/v1', '/upload/validate', [
            'methods' => 'POST',
            'callback' => [$this, 'validate_upload'],
            'permission_callback' => function () {
                return current_user_can('manage_options');
            },
        ]);

        register_rest_route('modelora/v1', '/models/upload', [
            'methods' => 'POST',
            'callback' => [$this, 'handle_upload'],
            'permission_callback' => function () {
                return current_user_can('manage_options');
            },
        ]);

        register_rest_route('modelora/v1', '/models/url', [
            'methods' => 'POST',
            'callback' => [$this, 'create_model_from_url'],
            'permission_callback' => function () {
                return current_user_can('manage_options');
            },
        ]);

        register_rest_route('modelora/v1', '/models/(?P<id>\d+)/view-angle', [
            'methods' => 'POST',
            'callback' => [$this, 'save_default_view'],
            'permission_callback' => function () {
                return current_user_can('manage_options');
            },
        ]);

        register_rest_route('modelora/v1', '/models/demo', [
            'methods' => 'POST',
            'callback' => [$this, 'import_demo'],
            'permission_callback' => function () {
                return current_user_can('manage_options');
            },
        ]);
    }

    public function validate_upload(\WP_REST_Request $request)
    {
        $this->verify_nonce_or_die($request);
        
        $trace_id = $this->request_trace_id($request);
        $file = $request->get_file_params()['file'] ?? null;
        if (! $file) {
            $this->debug_log('upload_validate_missing_file', ['traceId' => $trace_id]);
            return new \WP_REST_Response(['success' => false, 'error' => __('No file received.', 'modelora-3d-product-viewer'), 'trace_id' => $trace_id], 400);
        }

        $upload_manager = new UploadManager();
        $result = $upload_manager->validate_file($file);
        $this->debug_log('upload_validate_result', [
            'traceId' => $trace_id,
            'filename' => (string) ($file['name'] ?? ''),
            'size' => (int) ($file['size'] ?? 0),
            'success' => ! empty($result['success']),
            'error' => (string) ($result['error'] ?? ''),
        ]);

        $result['trace_id'] = $trace_id;

        return new \WP_REST_Response($result, $result['success'] ? 200 : 400);
    }

    public function handle_upload(\WP_REST_Request $request)
    {
        $this->verify_nonce_or_die($request);
        
        $trace_id = $this->request_trace_id($request);
        $files = $request->get_file_params();
        $output_dir_raw = (string) $request->get_param('outputDir');
        
        // FIX: Sanitize to prevent directory traversal - remove forward slashes
        $output_dir = trim(preg_replace('/[^a-zA-Z0-9_-]/', '', $output_dir_raw), '/');
        
        $conversion_meta = [
            'source_extension' => sanitize_key((string) $request->get_param('sourceExtension')),
            'compression' => sanitize_key((string) $request->get_param('compression')),
            'embed_resources' => (int) $request->get_param('embedResources') === 1 ? 1 : 0,
            'preserve_transform' => (int) $request->get_param('preserveTransform') === 1 ? 1 : 0,
        ];
        $conversion_warnings_raw = $request->get_param('conversionWarnings');
        $conversion_warnings = [];
        if (is_string($conversion_warnings_raw) && $conversion_warnings_raw !== '') {
            $decoded = json_decode(wp_unslash($conversion_warnings_raw), true);
            if (is_array($decoded)) {
                foreach ($decoded as $warning) {
                    if (is_scalar($warning)) {
                        $conversion_warnings[] = sanitize_text_field((string) $warning);
                    }
                }
            }
        }

        $this->debug_log('upload_start', [
            'traceId' => $trace_id,
            'hasFile' => ! empty($files['file']),
            'outputDir' => $output_dir,
            'conversionMeta' => $conversion_meta,
        ]);

        if (empty($files['file'])) {
            $this->debug_log('upload_missing_file', ['traceId' => $trace_id]);
            return new \WP_REST_Response(['success' => false, 'message' => __('No file uploaded.', 'modelora-3d-product-viewer'), 'trace_id' => $trace_id], 400);
        }

        $upload_manager = new UploadManager();
        $validation = $upload_manager->validate_file($files['file']);
        if (! $validation['success']) {
            $this->debug_log('upload_validation_failed', [
                'traceId' => $trace_id,
                'filename' => (string) ($files['file']['name'] ?? ''),
                'error' => (string) ($validation['error'] ?? ''),
            ]);
            return new \WP_REST_Response(['success' => false, 'message' => $validation['error'], 'trace_id' => $trace_id], 400);
        }

        if (! function_exists('wp_handle_upload')) {
            require_once ABSPATH . 'wp-admin/includes/file.php';
        }

        $upload_overrides = ['test_form' => false];
        $upload_dir_filter = null;
        if ($output_dir !== '') {
            $upload_dir_filter = function (array $dirs) use ($output_dir): array {
                // Validate output directory stays within base upload directory
                $subdir = '/' . ltrim($output_dir, '/');
                $base_path = realpath($dirs['basedir']);
                $target_path = realpath($dirs['basedir'] . $subdir);
                
                // Ensure target is within base (prevent directory traversal)
                if ($base_path && $target_path && strpos($target_path, $base_path) !== 0) {
                    $this->debug_log('upload_path_traversal_blocked', ['traceId' => $this->build_trace_id(), 'attemptedPath' => $output_dir]);
                    return $dirs;
                }
                
                $dirs['subdir'] = $subdir;
                $dirs['path'] = $dirs['basedir'] . $subdir;
                $dirs['url'] = $dirs['baseurl'] . $subdir;
                if (! wp_mkdir_p($dirs['path'])) {
                    return $dirs;
                }
                return $dirs;
            };
            add_filter('upload_dir', $upload_dir_filter);
        }

        try {
            $movefile = wp_handle_upload($files['file'], $upload_overrides);
        } finally {
            if (is_callable($upload_dir_filter)) {
                remove_filter('upload_dir', $upload_dir_filter);
            }
        }

        if ($movefile && ! isset($movefile['error'])) {
            $filename = basename($files['file']['name']);
            $post_id = wp_insert_post([
                'post_title' => preg_replace('/\.[^.]+$/', '', sanitize_file_name($filename)),
                'post_type' => 'modelora_model',
                'post_status' => 'publish',
            ]);

            if (is_wp_error($post_id)) {
                $this->debug_log('upload_model_post_failed', [
                    'traceId' => $trace_id,
                    'error' => $post_id->get_error_message(),
                ]);
                return new \WP_REST_Response(['success' => false, 'message' => __('Failed to create model post.', 'modelora-3d-product-viewer'), 'trace_id' => $trace_id], 500);
            }

            $attachment = [
                'post_mime_type' => $movefile['type'],
                'post_title'     => preg_replace('/\.[^.]+$/', '', $filename),
                'post_content'   => '',
                'post_status'    => 'inherit',
            ];
            $attach_id = wp_insert_attachment($attachment, $movefile['file'], $post_id);

            update_post_meta($post_id, '_modelora_model_glb_url', $movefile['url']);
            update_post_meta($post_id, '_modelora_attachment_id', $attach_id);
            if (! empty($conversion_meta['source_extension'])) {
                update_post_meta($post_id, '_modelora_conversion_meta', $conversion_meta);
            }

            $validator_result = apply_filters('modelora_validate_glb', null, $movefile['file'], $movefile['url'], $trace_id, $post_id);
            $validator_errors = [];
            $validator_warnings = [];
            if (is_array($validator_result)) {
                $validator_errors = is_array($validator_result['errors'] ?? null) ? $validator_result['errors'] : [];
                $validator_warnings = is_array($validator_result['warnings'] ?? null) ? $validator_result['warnings'] : [];
            }

            if (! empty($validator_errors)) {
                wp_delete_attachment($attach_id, true);
                wp_delete_post($post_id, true);
                $this->debug_log('upload_validator_failed', [
                    'traceId' => $trace_id,
                    'errors' => $validator_errors,
                ]);

                return new \WP_REST_Response([
                    'success' => false,
                    'message' => __('Converted GLB failed validation.', 'modelora-3d-product-viewer'),
                    'validation_errors' => $validator_errors,
                    'trace_id' => $trace_id,
                ], 422);
            }

            if (! empty($validator_warnings)) {
                $conversion_warnings = array_merge($conversion_warnings, $validator_warnings);
            }

            if (! empty($conversion_warnings)) {
                update_post_meta($post_id, '_modelora_conversion_warnings', $conversion_warnings);
            }
            $this->debug_log('upload_success', [
                'traceId' => $trace_id,
                'modelId' => (int) $post_id,
                'attachmentId' => (int) $attach_id,
                'url' => (string) $movefile['url'],
                'path' => (string) $movefile['file'],
                'conversionWarningsCount' => count($conversion_warnings),
            ]);

            return new \WP_REST_Response([
                'success' => true,
                'model_id' => $post_id,
                'url' => $movefile['url'],
                'file_path' => $movefile['file'],
                'warnings' => $conversion_warnings,
                'trace_id' => $trace_id,
            ]);
        }

        $this->debug_log('upload_failed', [
            'traceId' => $trace_id,
            'error' => (string) ($movefile['error'] ?? ''),
        ]);

        return new \WP_REST_Response(['success' => false, 'message' => $movefile['error'] ?? __('Upload failed.', 'modelora-3d-product-viewer'), 'trace_id' => $trace_id], 500);
    }

    public function save_default_view(\WP_REST_Request $request)
    {
        $this->verify_nonce_or_die($request);
        
        $trace_id = $this->request_trace_id($request);
        $id = (int) $request['id'];
        $orbit = sanitize_text_field((string) $request->get_param('cameraOrbit'));
        $target = sanitize_text_field((string) $request->get_param('cameraTarget'));

        if (! $id || get_post_type($id) !== 'modelora_model') {
            $this->debug_log('save_view_invalid_model', ['traceId' => $trace_id, 'modelId' => $id]);
            return new \WP_REST_Response(['success' => false, 'message' => __('Invalid model.', 'modelora-3d-product-viewer'), 'trace_id' => $trace_id], 404);
        }

        update_post_meta($id, '_modelora_camera_orbit', $orbit);
        update_post_meta($id, '_modelora_camera_target', $target);
        $this->debug_log('save_view_success', [
            'traceId' => $trace_id,
            'modelId' => $id,
            'cameraOrbit' => $orbit,
            'cameraTarget' => $target,
        ]);

        return new \WP_REST_Response(['success' => true, 'trace_id' => $trace_id]);
    }

    public function create_model_from_url(\WP_REST_Request $request)
    {
        $this->verify_nonce_or_die($request);
        
        $trace_id = $this->request_trace_id($request);
        $model_url_raw = (string) $request->get_param('modelUrl');
        $model_url = esc_url_raw(trim($model_url_raw));
        $title_raw = (string) $request->get_param('title');
        $title = sanitize_text_field($title_raw);

        $this->debug_log('url_model_create_start', [
            'traceId' => $trace_id,
            'modelUrl' => $model_url,
            'title' => $title,
        ]);

        if ($model_url === '') {
            return new \WP_REST_Response([
                'success' => false,
                'message' => __('Model URL is required.', 'modelora-3d-product-viewer'),
                'trace_id' => $trace_id,
            ], 400);
        }

        $parts = wp_parse_url($model_url);
        $scheme = strtolower((string) ($parts['scheme'] ?? ''));
        if (! in_array($scheme, ['http', 'https'], true)) {
            return new \WP_REST_Response([
                'success' => false,
                'message' => __('Only http/https model URLs are allowed.', 'modelora-3d-product-viewer'),
                'trace_id' => $trace_id,
            ], 400);
        }

        $path = (string) ($parts['path'] ?? '');
        $extension = strtolower((string) pathinfo($path, PATHINFO_EXTENSION));
        if (! in_array($extension, ['glb', 'gltf', 'usdz'], true)) {
            return new \WP_REST_Response([
                'success' => false,
                'message' => __('Only GLB, GLTF, or USDZ URLs are supported for direct linking.', 'modelora-3d-product-viewer'),
                'trace_id' => $trace_id,
            ], 400);
        }

        if ($title === '') {
            $basename = (string) pathinfo($path, PATHINFO_FILENAME);
            $title = $basename !== '' ? sanitize_text_field(str_replace(['-', '_'], ' ', $basename)) : __('Remote 3D Model', 'modelora-3d-product-viewer');
        }

        $post_id = wp_insert_post([
            'post_title' => $title,
            'post_type' => 'modelora_model',
            'post_status' => 'publish',
        ]);

        if (is_wp_error($post_id)) {
            $this->debug_log('url_model_create_post_failed', [
                'traceId' => $trace_id,
                'error' => $post_id->get_error_message(),
            ]);
            return new \WP_REST_Response([
                'success' => false,
                'message' => __('Failed to create model post.', 'modelora-3d-product-viewer'),
                'trace_id' => $trace_id,
            ], 500);
        }

        update_post_meta($post_id, '_modelora_model_glb_url', $model_url);
        update_post_meta($post_id, '_modelora_model_source', 'remote_url');

        $this->debug_log('url_model_create_success', [
            'traceId' => $trace_id,
            'modelId' => (int) $post_id,
            'url' => $model_url,
            'extension' => $extension,
        ]);

        return new \WP_REST_Response([
            'success' => true,
            'model_id' => $post_id,
            'url' => $model_url,
            'trace_id' => $trace_id,
        ]);
    }

    public function import_demo(\WP_REST_Request $request)
    {
        $this->verify_nonce_or_die($request);
        
        $trace_id = $this->request_trace_id($request);
        $this->debug_log('demo_import_start', ['traceId' => $trace_id, 'type' => 'local']);
        
        $local_demo_path = MODELORA_PLUGIN_DIR . 'assets/demo/demo-model.glb';
        
        if (! file_exists($local_demo_path)) {
            return new \WP_REST_Response(['success' => false, 'message' => __('Demo model file missing in plugin.', 'modelora-3d-product-viewer'), 'trace_id' => $trace_id], 500);
        }

        if (! function_exists('wp_tempnam')) {
            require_once ABSPATH . 'wp-admin/includes/file.php';
        }
        
        $tmp = wp_tempnam($local_demo_path);
        if (! copy($local_demo_path, $tmp)) {
            return new \WP_REST_Response(['success' => false, 'message' => __('Failed to copy demo model.', 'modelora-3d-product-viewer'), 'trace_id' => $trace_id], 500);
        }

        $file_array = [
            'name'     => 'demo-model.glb',
            'tmp_name' => $tmp
        ];

        $post_id = wp_insert_post([
            'post_title' => 'Demo Model',
            'post_type' => 'modelora_model',
            'post_status' => 'publish',
        ]);

        if (is_wp_error($post_id)) {
            wp_delete_file($tmp);
            $this->debug_log('demo_import_post_failed', ['traceId' => $trace_id, 'error' => $post_id->get_error_message()]);
            return new \WP_REST_Response(['success' => false, 'message' => __('Failed to create demo model.', 'modelora-3d-product-viewer'), 'trace_id' => $trace_id], 500);
        }

        if (! function_exists('media_handle_sideload')) {
            require_once ABSPATH . 'wp-admin/includes/file.php';
            require_once ABSPATH . 'wp-admin/includes/media.php';
            require_once ABSPATH . 'wp-admin/includes/image.php';
        }

        $attach_id = media_handle_sideload($file_array, $post_id);
        
        if (is_wp_error($attach_id)) {
            wp_delete_file($tmp);
            wp_delete_post($post_id, true);
            $this->debug_log('demo_import_attach_failed', ['traceId' => $trace_id, 'error' => $attach_id->get_error_message()]);
            return new \WP_REST_Response(['success' => false, 'message' => $attach_id->get_error_message(), 'trace_id' => $trace_id], 500);
        }

        // FIX: Check if $url exists before using it
        $url = wp_get_attachment_url($attach_id);
        if (! $url) {
            wp_delete_attachment($attach_id, true);
            wp_delete_post($post_id, true);
            $this->debug_log('demo_import_url_failed', ['traceId' => $trace_id]);
            return new \WP_REST_Response(['success' => false, 'message' => __('Failed to get attachment URL.', 'modelora-3d-product-viewer'), 'trace_id' => $trace_id], 500);
        }

        update_post_meta($post_id, '_modelora_model_glb_url', $url);
        update_post_meta($post_id, '_modelora_attachment_id', $attach_id);
        $this->debug_log('demo_import_success', [
            'traceId' => $trace_id,
            'modelId' => (int) $post_id,
            'attachmentId' => (int) $attach_id,
            'url' => (string) $url,
        ]);

        return new \WP_REST_Response([
            'success' => true,
            'model_id' => $post_id,
            'url' => $url,
            'trace_id' => $trace_id,
        ]);
    }
}

