<?php
declare(strict_types=1);
defined('ABSPATH') || exit;

class DSProofwp_Import_Controller
{
    private const ROUTE_NAMESPACE = 'dsproofwp/v1';
    private const JUDGEME_MAX_MEDIA_ITEMS = 5;
    private const ALIEXPRESS_MAX_MEDIA_ITEMS = 5;

    private DSProofwp_Review_Repository $review_repository;
    private DSProofwp_Review_Media_Repository $media_repository;

    public function __construct(
        DSProofwp_Review_Repository $review_repository,
        DSProofwp_Review_Media_Repository $media_repository
    ) {
        $this->review_repository = $review_repository;
        $this->media_repository  = $media_repository;
    }

    public function register_routes(): void
    {
        register_rest_route(
            self::ROUTE_NAMESPACE,
            '/reviews/import/judgeme',
            [
                [
                    'methods'             => WP_REST_Server::CREATABLE,
                    'callback'            => [$this, 'import_judgeme_reviews'],
                    'permission_callback' => [$this, 'manage_permission'],
                ],
            ]
        );

        register_rest_route(
            self::ROUTE_NAMESPACE,
            '/reviews/import/cusrev/status',
            [
                [
                    'methods'             => WP_REST_Server::READABLE,
                    'callback'            => [$this, 'get_cusrev_migration_status'],
                    'permission_callback' => [$this, 'manage_permission'],
                ],
            ]
        );

        register_rest_route(
            self::ROUTE_NAMESPACE,
            '/reviews/import/cusrev/migrate',
            [
                [
                    'methods'             => WP_REST_Server::CREATABLE,
                    'callback'            => [$this, 'migrate_cusrev_reviews'],
                    'permission_callback' => [$this, 'manage_permission'],
                ],
            ]
        );

        register_rest_route(
            self::ROUTE_NAMESPACE,
            '/reviews/import/reviewx/status',
            [
                [
                    'methods'             => WP_REST_Server::READABLE,
                    'callback'            => [$this, 'get_reviewx_migration_status'],
                    'permission_callback' => [$this, 'manage_permission'],
                ],
            ]
        );

        register_rest_route(
            self::ROUTE_NAMESPACE,
            '/reviews/import/reviewx/migrate',
            [
                [
                    'methods'             => WP_REST_Server::CREATABLE,
                    'callback'            => [$this, 'migrate_reviewx_reviews'],
                    'permission_callback' => [$this, 'manage_permission'],
                ],
            ]
        );

        register_rest_route(
            self::ROUTE_NAMESPACE,
            '/reviews/import/aliexpress/fetch',
            [
                [
                    'methods'             => WP_REST_Server::CREATABLE,
                    'callback'            => [$this, 'fetch_aliexpress_reviews'],
                    'permission_callback' => [$this, 'manage_permission'],
                ],
            ]
        );

        register_rest_route(
            self::ROUTE_NAMESPACE,
            '/reviews/import/aliexpress/import',
            [
                [
                    'methods'             => WP_REST_Server::CREATABLE,
                    'callback'            => [$this, 'import_aliexpress_reviews'],
                    'permission_callback' => [$this, 'manage_permission'],
                ],
            ]
        );
    }

    public function import_judgeme_reviews(WP_REST_Request $request)
    {
        $file = $this->get_uploaded_csv_file($request);

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

        $handle = fopen($file['tmp_name'], 'r');

        if ($handle === false) {
            return new WP_Error('dsproofwp_judgeme_import_open_failed', 'Failed to open the uploaded CSV file.', ['status' => 400]);
        }

        $header = fgetcsv($handle);

        if (! is_array($header) || $header === []) {
            fclose($handle);

            return new WP_Error('dsproofwp_judgeme_import_invalid_header', 'The uploaded CSV file is empty or invalid.', ['status' => 400]);
        }

        $normalized_header = array_map([$this, 'normalize_csv_value'], $header);
        $required_columns  = ['body', 'rating'];

        foreach ($required_columns as $column) {
            if (! in_array($column, $normalized_header, true)) {
                fclose($handle);

                return new WP_Error(
                    'dsproofwp_judgeme_import_missing_columns',
                    sprintf('The uploaded CSV file is missing the required "%s" column.', $column),
                    ['status' => 400]
                );
            }
        }

        $summary = [
            'imported' => 0,
            'skipped'  => 0,
        ];

        while (($row = fgetcsv($handle)) !== false) {
            if (! is_array($row) || $this->is_empty_csv_row($row)) {
                continue;
            }

            $record = $this->combine_csv_row($normalized_header, $row);

            $body = trim((string) ($record['body'] ?? ''));
            if ($body === '') {
                $summary['skipped']++;
                continue;
            }

            $rating = $this->sanitize_import_rating($record['rating'] ?? null);
            if ($rating === null) {
                $summary['skipped']++;
                continue;
            }

            $payload = [
                'product_id'   => $this->resolve_product_id_from_slug((string) ($record['product_handle'] ?? '')),
                'author_name'  => $this->resolve_import_author_name($record['reviewer_name'] ?? ''),
                'author_email' => sanitize_email((string) ($record['reviewer_email'] ?? '')),
                'content'      => $body,
                'source'       => 'judgeme',
                'status'       => '1',
                'rating'       => $rating,
                'date'         => (string) ($record['review_date'] ?? ''),
                'media'        => $this->sideload_judgeme_media((string) ($record['picture_urls'] ?? '')),
                'is_visual'    => ! empty($record['picture_urls']),
            ];

            $review = $this->review_repository->create($payload);

            if (! $review) {
                $summary['skipped']++;
                continue;
            }

            if ($payload['media'] !== []) {
                $this->media_repository->store_for_review((int) $review['id'], $payload['media']);
                $this->review_repository->update((int) $review['id'], ['is_visual' => true]);
            }

            $summary['imported']++;
        }

        fclose($handle);

        return rest_ensure_response($summary);
    }

    public function get_cusrev_migration_status(WP_REST_Request $request)
    {
        $stats = $this->review_repository->get_cusrev_stats();
        
        return rest_ensure_response([
            'detected' => $stats['count'] > 0,
            'count'    => $stats['count'],
        ]);
    }

    public function migrate_cusrev_reviews(WP_REST_Request $request)
    {
        $limit = 50; // Process in batches
        $ids = $this->review_repository->get_unmigrated_cusrev_ids($limit);

        $summary = [
            'migrated' => 0,
            'skipped'  => 0,
            'errors'   => 0,
        ];

        if (empty($ids)) {
            return rest_ensure_response($summary);
        }

        foreach ($ids as $comment_id) {
            try {
                $has_media = false;
                $media_items = [];

                // 1. Check for Local Images (Attachment IDs)
                $local_images_meta = get_comment_meta($comment_id, 'ivole_review_image2', false);
                error_log("ProofWP Debug: Migrating Comment ID: " . $comment_id);
                error_log("ProofWP Debug: CusRev Local Image Meta: " . print_r($local_images_meta, true));
                if (!empty($local_images_meta) && is_array($local_images_meta)) {
                    foreach ($local_images_meta as $meta_value) {
                        // CusRev might store a single ID or an array of IDs in one meta row
                        $attachment_ids = is_array($meta_value) ? $meta_value : array($meta_value);
                        foreach ($attachment_ids as $attachment_id) {
                            if (is_numeric($attachment_id)) {
                                $url = wp_get_attachment_url((int) $attachment_id);
                                error_log("ProofWP Debug: Image Attachment ID: " . $attachment_id . " URL: " . $url);
                                if ($url) {
                                    $media_items[] = [
                                        'attachment_id' => (int) $attachment_id,
                                        'media_type'    => 'image',
                                        'url'           => $url,
                                    ];
                                    $has_media = true;
                                }
                            }
                        }
                    }
                }

                // 2. Check for Cloud Images (URLs)
                $cloud_images_meta = get_comment_meta($comment_id, 'ivole_review_image', false);
                error_log("ProofWP Debug: CusRev Cloud Image Meta: " . print_r($cloud_images_meta, true));
                if (!empty($cloud_images_meta) && is_array($cloud_images_meta)) {
                    foreach ($cloud_images_meta as $meta_value) {
                        $items = is_array($meta_value) ? $meta_value : array($meta_value);
                        foreach ($items as $item) {
                            $image_url = "";
                            if (is_array($item) && isset($item['url'])) {
                                $image_url = $item['url'];
                            } elseif (is_string($item)) {
                                $image_url = $item;
                            }

                            if (!empty($image_url)) {
                                // Avoid duplicates if already added from local
                                $exists = false;
                                foreach ($media_items as $mi) {
                                    if ($mi['url'] === $image_url) {
                                        $exists = true;
                                        break;
                                    }
                                }
                                if (!$exists) {
                                    $media_items[] = [
                                        'attachment_id' => null,
                                        'media_type'    => 'image',
                                        'url'           => $image_url,
                                    ];
                                    $has_media = true;
                                }
                            }
                        }
                    }
                }

                // 3. Check for Local Videos (Attachment IDs)
                $local_videos_meta = get_comment_meta($comment_id, 'ivole_review_video2', false);
                error_log("ProofWP Debug: CusRev Local Video Meta: " . print_r($local_videos_meta, true));
                if (!empty($local_videos_meta) && is_array($local_videos_meta)) {
                    foreach ($local_videos_meta as $meta_value) {
                        $attachment_ids = is_array($meta_value) ? $meta_value : array($meta_value);
                        foreach ($attachment_ids as $attachment_id) {
                            if (is_numeric($attachment_id)) {
                                $url = wp_get_attachment_url((int) $attachment_id);
                                if ($url) {
                                    $media_items[] = [
                                        'attachment_id' => (int) $attachment_id,
                                        'media_type'    => 'video',
                                        'url'           => $url,
                                    ];
                                    $has_media = true;
                                }
                            }
                        }
                    }
                }

                // 4. Check for Cloud Videos (URLs)
                $cloud_videos_meta = get_comment_meta($comment_id, 'ivole_review_video', false);
                if (!empty($cloud_videos_meta) && is_array($cloud_videos_meta)) {
                    foreach ($cloud_videos_meta as $meta_value) {
                        $items = is_array($meta_value) ? $meta_value : array($meta_value);
                        foreach ($items as $item) {
                            $video_url = "";
                            if (is_array($item) && isset($item['url'])) {
                                $video_url = $item['url'];
                            } elseif (is_string($item)) {
                                $video_url = $item;
                            }

                            if (!empty($video_url)) {
                                $exists = false;
                                foreach ($media_items as $mi) {
                                    if ($mi['url'] === $video_url) {
                                        $exists = true;
                                        break;
                                    }
                                }
                                if (!$exists) {
                                    $media_items[] = [
                                        'attachment_id' => null,
                                        'media_type'    => 'video',
                                        'url'           => $video_url,
                                    ];
                                    $has_media = true;
                                }
                            }
                        }
                    }
                }

                // Register as ProofWP review
                $this->review_repository->register_as_proofwp_review($comment_id, 'customer-reviews-woocommerce', $has_media);

                // Store media if any
                if ($has_media) {
                    $this->media_repository->store_for_review($comment_id, $media_items);
                }

                $summary['migrated']++;
            } catch (Exception $e) {
                $summary['errors']++;
            }
        }

        return rest_ensure_response($summary);
    }

    public function get_reviewx_migration_status(WP_REST_Request $request)
    {
        $stats = $this->review_repository->get_reviewx_stats();
        
        return rest_ensure_response([
            'detected' => $stats['count'] > 0,
            'count'    => $stats['count'],
        ]);
    }

    public function migrate_reviewx_reviews(WP_REST_Request $request)
    {
        $limit = 50; // Process in batches
        $ids = $this->review_repository->get_unmigrated_reviewx_ids($limit);
        
        $summary = [
            'migrated' => 0,
            'skipped'  => 0,
            'errors'   => 0,
        ];

        if (empty($ids)) {
            return rest_ensure_response($summary);
        }

        foreach ($ids as $comment_id) {
            try {
                $has_media = false;
                $media_items = [];

                // 1. Map Status if needed
                // ReviewX: 1 = approved, hold = pending
                // WP Comments: 1 = approved, 0 = unapproved (hold)
                $current_status = wp_get_comment_status($comment_id);
                if ($current_status === 'unapproved') {
                    // ReviewX uses 'hold' which maps to WP 'unapproved'
                }

                // 2. Process Media
                $attachments = get_comment_meta($comment_id, 'rvx_attachments', true);
                if (!empty($attachments)) {
                    $attachments = maybe_unserialize($attachments);
                    if (is_array($attachments)) {
                        foreach ($attachments as $url) {
                            if (is_string($url) && !empty($url)) {
                                $media_items[] = [
                                    'attachment_id' => null, // URLs, not WP Attachments
                                    'media_type'    => 'image', // Assume image based on example
                                    'url'           => esc_url_raw($url),
                                ];
                                $has_media = true;
                            }
                        }
                    }
                }

                // 3. Register as ProofWP review
                $this->review_repository->register_as_proofwp_review($comment_id, 'reviewx', $has_media);

                // 4. Store media if any
                if ($has_media) {
                    $this->media_repository->store_for_review($comment_id, $media_items);
                }

                $summary['migrated']++;
            } catch (Exception $e) {
                $summary['errors']++;
            }
        }

        return rest_ensure_response($summary);
    }

    public function fetch_aliexpress_reviews(WP_REST_Request $request)
    {
        $body      = $request->get_json_params();
        $url       = sanitize_text_field((string) ($body['url'] ?? ''));
        $translate = (bool) ($body['translate'] ?? true);

        $scraper    = new DSProofwp_AliExpress_Scraper();
        $product_id = $scraper->extract_product_id($url);

        if ($product_id === null) {
            return new WP_Error(
                'dsproofwp_aliexpress_invalid_url',
                'The provided URL is not a valid AliExpress product URL.',
                ['status' => 400]
            );
        }

        $result = $scraper->fetch_page($product_id, 1, $translate);

        if (! empty($result['error'])) {
            return new WP_Error(
                'dsproofwp_aliexpress_fetch_failed',
                $result['error'],
                ['status' => 502]
            );
        }

        return rest_ensure_response([
            'aliexpress_product_id' => $product_id,
            'total_reviews'         => $result['total'],
            'average_rating'        => $result['average_rating'],
            'reviews'               => $result['reviews'],
        ]);
    }

    public function import_aliexpress_reviews(WP_REST_Request $request)
    {
        $body             = $request->get_json_params();
        $url              = sanitize_text_field((string) ($body['url'] ?? ''));
        $product_id       = (int) ($body['product_id'] ?? 0);
        $min_rating       = (int) ($body['min_rating'] ?? 1);
        $with_photos_only = (bool) ($body['with_photos_only'] ?? false);
        $translate        = (bool) ($body['translate'] ?? true);

        if ($product_id > 0 && (! function_exists('wc_get_product') || ! wc_get_product($product_id))) {
            return new WP_Error(
                'dsproofwp_aliexpress_invalid_product',
                'The specified WooCommerce product was not found.',
                ['status' => 404]
            );
        }

        $scraper              = new DSProofwp_AliExpress_Scraper();
        $aliexpress_product_id = $scraper->extract_product_id($url);

        if ($aliexpress_product_id === null) {
            return new WP_Error(
                'dsproofwp_aliexpress_invalid_url',
                'The provided URL is not a valid AliExpress product URL.',
                ['status' => 400]
            );
        }

        $filter = $with_photos_only ? 'image' : 'all';
        $result = $scraper->fetch_all($aliexpress_product_id, $translate, $filter);

        if (! empty($result['error'])) {
            return new WP_Error(
                'dsproofwp_aliexpress_fetch_failed',
                $result['error'],
                ['status' => 502]
            );
        }

        $imported_count = 0;
        $skipped_count  = 0;

        foreach ($result['reviews'] as $review) {
            $rating  = (int) ($review['rating'] ?? 0);
            $content = trim((string) ($review['content'] ?? ''));
            $images  = (array) ($review['images'] ?? []);

            if ($rating < $min_rating) {
                $skipped_count++;
                continue;
            }

            if ($with_photos_only && empty($images)) {
                $skipped_count++;
                continue;
            }

            if ($content === '') {
                $skipped_count++;
                continue;
            }

            $payload = [
                'product_id'  => $product_id,
                'author_name' => sanitize_text_field((string) ($review['author_name'] ?? 'AliExpress Customer')),
                'content'     => $content,
                'source'      => 'aliexpress',
                'status'      => '1',
                'rating'      => $rating,
                'date'        => (string) ($review['date'] ?? ''),
            ];

            $created_review = $this->review_repository->create($payload);

            if (! $created_review) {
                $skipped_count++;
                continue;
            }

            $media = $this->sideload_external_images($images, self::ALIEXPRESS_MAX_MEDIA_ITEMS);

            if ($media !== []) {
                $this->media_repository->store_for_review((int) $created_review['id'], $media);
                $this->review_repository->update((int) $created_review['id'], ['is_visual' => true]);
            }

            $imported_count++;
        }

        return rest_ensure_response([
            'imported' => $imported_count,
            'skipped'  => $skipped_count,
        ]);
    }

    public function manage_permission(): bool
    {
        return current_user_can('manage_options');
    }

    private function sideload_judgeme_media(string $picture_urls): array
    {
        $picture_urls = trim($picture_urls);

        if ($picture_urls === '') {
            return [];
        }

        $urls = array_slice(array_map('trim', explode(',', $picture_urls)), 0, self::JUDGEME_MAX_MEDIA_ITEMS);

        return $this->sideload_external_images($urls, self::JUDGEME_MAX_MEDIA_ITEMS);
    }

    /**
     * Sideload external image URLs into the WordPress Media Library.
     *
     * @param string[] $image_urls Array of image URLs to sideload.
     * @param int      $max_items  Maximum number of images to process.
     *
     * @return array Array of media items with media_type, url, and optional attachment_id.
     */
    private function sideload_external_images(array $image_urls, int $max_items = 5): array
    {
        $urls  = array_slice($image_urls, 0, $max_items);
        $media = [];

        require_once ABSPATH . 'wp-admin/includes/image.php';
        require_once ABSPATH . 'wp-admin/includes/file.php';
        require_once ABSPATH . 'wp-admin/includes/media.php';

        foreach ($urls as $url) {
            $sanitized_url = esc_url_raw($url);

            if ($sanitized_url === '') {
                continue;
            }

            // Sideload the image into the Media Library
            $tmp = $this->download_external_file($sanitized_url);

            if (is_wp_error($tmp)) {
                // If download fails, we fallback to external URL (or we could skip it)
                $media[] = [
                    'media_type' => 'image',
                    'url'        => $sanitized_url,
                ];
                continue;
            }

            $file_array = [
                'name'     => basename($sanitized_url),
                'tmp_name' => $tmp,
            ];

            // Do the sideload
            $attachment_id = media_handle_sideload($file_array, 0);

            if (is_wp_error($attachment_id)) {
                @unlink($file_array['tmp_name']);
                $media[] = [
                    'media_type' => 'image',
                    'url'        => $sanitized_url,
                ];
                continue;
            }

            $local_url = wp_get_attachment_url($attachment_id);

            $media[] = [
                'media_type'    => 'image',
                'url'           => $local_url ?: $sanitized_url,
                'attachment_id' => $attachment_id,
            ];
        }

        return $media;
    }

    /**
     * Download a file from an external URL using native cURL.
     *
     * @param string $url The URL of the file to download.
     *
     * @return string|WP_Error Path to the temporary file on success, WP_Error on failure.
     */
    private function download_external_file(string $url)
    {
        $tmp_filename = wp_tempnam($url);

        if (! $tmp_filename) {
            return new WP_Error('dsproofwp_temp_file_creation_failed', 'Could not create a temporary file.');
        }

        $fp = fopen($tmp_filename, 'w+');

        if ($fp === false) {
            return new WP_Error('dsproofwp_temp_file_open_failed', 'Could not open the temporary file for writing.');
        }

        $ch = curl_init();

        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_FILE, $fp);
        curl_setopt($ch, CURLOPT_TIMEOUT, 15);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
        curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36',
            'Accept: image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8',
            'Accept-Language: en-US,en;q=0.5',
            'Referer: https://www.aliexpress.com/',
        ]);

        curl_exec($ch);

        if (curl_errno($ch)) {
            $error = curl_error($ch);
            curl_close($ch);
            fclose($fp);
            @unlink($tmp_filename);
            return new WP_Error('dsproofwp_download_failed', 'cURL error: ' . $error);
        }

        $status_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        fclose($fp);

        if ($status_code !== 200) {
            @unlink($tmp_filename);
            return new WP_Error('dsproofwp_download_failed', sprintf('Server returned HTTP %d.', $status_code));
        }

        return $tmp_filename;
    }

    private function get_uploaded_csv_file(WP_REST_Request $request)
    {
        $files = $request->get_file_params();
        $file  = $files['file'] ?? null;

        if (! is_array($file) || empty($file['tmp_name']) || ! empty($file['error'])) {
            return new WP_Error('dsproofwp_judgeme_import_missing_file', 'Please upload a CSV file.', ['status' => 400]);
        }

        $filename  = isset($file['name']) ? sanitize_file_name((string) $file['name']) : '';
        $extension = strtolower((string) pathinfo($filename, PATHINFO_EXTENSION));

        if ($extension !== 'csv') {
            return new WP_Error('dsproofwp_judgeme_import_invalid_file_type', 'Only CSV files are supported.', ['status' => 400]);
        }

        return $file;
    }

    private function normalize_csv_value($value): string
    {
        return trim((string) $value);
    }

    private function is_empty_csv_row(array $row): bool
    {
        foreach ($row as $value) {
            if (trim((string) $value) !== '') {
                return false;
            }
        }

        return true;
    }

    private function combine_csv_row(array $header, array $row): array
    {
        $row = array_pad($row, count($header), '');

        return array_combine($header, array_slice($row, 0, count($header))) ?: [];
    }

    private function sanitize_import_rating($rating): ?int
    {
        if ($rating === null || $rating === '') {
            return null;
        }

        if (! is_numeric($rating)) {
            return null;
        }

        $normalized_rating = (int) $rating;

        if ($normalized_rating < 1 || $normalized_rating > 5) {
            return null;
        }

        return $normalized_rating;
    }

    private function resolve_product_id_from_slug(string $product_slug): int
    {
        $product_slug = sanitize_title($product_slug);

        if ($product_slug === '') {
            return 0;
        }

        $product = get_page_by_path($product_slug, OBJECT, 'product');

        if (! $product instanceof WP_Post) {
            return 0;
        }

        return (int) $product->ID;
    }

    private function resolve_import_author_name($reviewer_name): string
    {
        $name = sanitize_text_field((string) $reviewer_name);

        if ($name !== '') {
            return $name;
        }

        return 'Judge.me Customer';
    }
}
