<?php
/**
 * ReviewService
 * Handles Business Logic for Customer Reviews, Ratings, and Image Uploads
 */

require_once __DIR__ . '/../Models/Review.php';
require_once __DIR__ . '/../Models/ReviewImage.php';
require_once __DIR__ . '/../Models/Report.php';
require_once __DIR__ . '/../Models/ActivityLog.php';

class ReviewService {
    private Review $reviewModel;
    private ReviewImage $reviewImageModel;
    private Report $reportModel;
    private ActivityLog $activityLog;

    private const MAX_IMAGES = 5;
    private const MAX_FILE_SIZE = 5242880; // 5MB in bytes
    private const ALLOWED_MIMES = ['image/jpeg', 'image/png', 'image/webp'];
    private const ALLOWED_EXTS = ['jpg', 'jpeg', 'png', 'webp'];

    public function __construct() {
        $this->reviewModel = new Review();
        $this->reviewImageModel = new ReviewImage();
        $this->reportModel = new Report();
        $this->activityLog = new ActivityLog();
    }

    /**
     * Check if user is eligible to review an item
     */
    public function checkEligibility(int $userId, int $orderItemId): array {
        return $this->reviewModel->checkEligibility($userId, $orderItemId);
    }

    /**
     * Submit a new customer review
     */
    public function submitReview(
        int $userId,
        int $orderItemId,
        int $rating,
        ?string $reviewText,
        array $uploadedFiles = [],
        bool $isAnonymous = false
    ): array {
        // 1. Check eligibility
        $eligibility = $this->reviewModel->checkEligibility($userId, $orderItemId);
        if (!$eligibility['eligible']) {
            return ['success' => false, 'message' => $eligibility['message']];
        }

        $item = $eligibility['item'];

        // 2. Validate rating
        if ($rating < 1 || $rating > 5) {
            return ['success' => false, 'message' => 'กรุณาให้คะแนนระหว่าง 1 ถึง 5 ดาว'];
        }

        // 3. Validate text length
        $reviewText = trim((string)$reviewText);
        if (mb_strlen($reviewText) > 2000) {
            return ['success' => false, 'message' => 'ข้อความรีวิวต้องไม่เกิน 2,000 ตัวอักษร'];
        }

        // 4. Process and upload review images
        $imagePaths = [];
        if (!empty($uploadedFiles['name']) && is_array($uploadedFiles['name'])) {
            $uploadResult = $this->processImageUploads($uploadedFiles, self::MAX_IMAGES);
            if (!$uploadResult['success']) {
                return $uploadResult;
            }
            $imagePaths = $uploadResult['paths'];
        }

        // 5. Save to database
        try {
            $reviewId = $this->reviewModel->createReview([
                'order_id'      => (int)$item['order_id'],
                'order_item_id' => $orderItemId,
                'product_id'    => (int)$item['product_id'],
                'store_id'      => (int)$item['store_id'],
                'user_id'       => $userId,
                'rating'        => $rating,
                'review_text'   => !empty($reviewText) ? $reviewText : null,
                'is_anonymous'  => $isAnonymous
            ], $imagePaths);

            $this->activityLog->record($userId, 'review_submitted', 'review', $reviewId, "Submitted review for product ID {$item['product_id']}");

            return [
                'success'   => true,
                'message'   => 'ส่งรีวิวสินค้าเรียบร้อยแล้ว ขอบคุณสำหรับความคิดเห็นของคุณ',
                'review_id' => $reviewId
            ];
        } catch (Exception $e) {
            // Clean up uploaded images on error
            foreach ($imagePaths as $path) {
                $full = __DIR__ . '/../../' . ltrim($path, '/');
                if (file_exists($full)) {
                    @unlink($full);
                }
            }
            return ['success' => false, 'message' => 'เกิดข้อผิดพลาดในการบันทึกรีวิว: ' . $e->getMessage()];
        }
    }

    /**
     * Update an existing review
     */
    public function updateReview(
        int $userId,
        int $reviewId,
        int $rating,
        ?string $reviewText,
        array $newUploadedFiles = [],
        array $deleteImageIds = [],
        bool $isAnonymous = false
    ): array {
        $review = $this->reviewModel->findById($reviewId);
        if (!$review || (int)$review['user_id'] !== $userId) {
            return ['success' => false, 'message' => 'ไม่พบรีวิวหรือคุณไม่มีสิทธิ์แก้ไข'];
        }

        if ($review['status'] === 'removed') {
            return ['success' => false, 'message' => 'รีวิวนี้ถูกลบแล้ว ไม่สามารถแก้ไขได้'];
        }

        // Validate rating
        if ($rating < 1 || $rating > 5) {
            return ['success' => false, 'message' => 'กรุณาให้คะแนนระหว่าง 1 ถึง 5 ดาว'];
        }

        $reviewText = trim((string)$reviewText);
        if (mb_strlen($reviewText) > 2000) {
            return ['success' => false, 'message' => 'ข้อความรีวิวต้องไม่เกิน 2,000 ตัวอักษร'];
        }

        // Calculate allowed new images
        $existingImages = $this->reviewImageModel->getImagesByReview($reviewId);
        $remainingCount = count($existingImages) - count($deleteImageIds);
        $maxNew = max(0, self::MAX_IMAGES - $remainingCount);

        $newImagePaths = [];
        if (!empty($newUploadedFiles['name']) && is_array($newUploadedFiles['name']) && $maxNew > 0) {
            $uploadResult = $this->processImageUploads($newUploadedFiles, $maxNew);
            if (!$uploadResult['success']) {
                return $uploadResult;
            }
            $newImagePaths = $uploadResult['paths'];
        }

        try {
            $updated = $this->reviewModel->updateReview(
                $reviewId,
                $userId,
                $rating,
                !empty($reviewText) ? $reviewText : null,
                $isAnonymous,
                $newImagePaths,
                $deleteImageIds
            );

            if ($updated) {
                $this->activityLog->record($userId, 'review_updated', 'review', $reviewId, "Updated review #{$reviewId}");
                return ['success' => true, 'message' => 'แก้ไขรีวิวสินค้าเรียบร้อยแล้ว'];
            }

            return ['success' => false, 'message' => 'ไม่สามารถแก้ไขรีวิวได้'];
        } catch (Exception $e) {
            return ['success' => false, 'message' => 'เกิดข้อผิดพลาด: ' . $e->getMessage()];
        }
    }

    /**
     * Delete review by user
     */
    public function deleteReview(int $userId, int $reviewId): array {
        $review = $this->reviewModel->findById($reviewId);
        if (!$review || (int)$review['user_id'] !== $userId) {
            return ['success' => false, 'message' => 'ไม่พบรีวิวหรือคุณไม่มีสิทธิ์ลบ'];
        }

        $deleted = $this->reviewModel->deleteReview($reviewId, $userId);
        if ($deleted) {
            $this->activityLog->record($userId, 'review_deleted', 'review', $reviewId, "Deleted review #{$reviewId}");
            return ['success' => true, 'message' => 'ลบรีวิวเรียบร้อยแล้ว'];
        }

        return ['success' => false, 'message' => 'ไม่สามารถลบรีวิวได้'];
    }

    /**
     * Get Product Reviews and Rating Statistics
     */
    public function getProductReviews(int $productId, int $page = 1, int $perPage = 10, ?int $rating = null): array {
        $page = max(1, $page);
        $offset = ($page - 1) * $perPage;

        $reviews = $this->reviewModel->getProductReviews($productId, $perPage, $offset, $rating);
        $totalCount = $this->reviewModel->countProductReviews($productId, $rating);
        $breakdown = $this->reviewModel->getProductRatingBreakdown($productId);

        return [
            'reviews'     => $reviews,
            'breakdown'   => $breakdown,
            'total_count' => $totalCount,
            'page'        => $page,
            'per_page'    => $perPage,
            'total_pages' => ceil($totalCount / $perPage),
            'rating_filter' => $rating
        ];
    }

    public function getProductRatingBreakdown(int $productId): array {
        return $this->reviewModel->getProductRatingBreakdown($productId);
    }

    /**
     * Get Store Reviews for Seller
     */
    public function getStoreReviews(int $storeId, array $filters = [], int $page = 1, int $perPage = 20): array {
        $page = max(1, $page);
        $offset = ($page - 1) * $perPage;

        $reviews = $this->reviewModel->getStoreReviews($storeId, $filters, $perPage, $offset);
        $totalCount = $this->reviewModel->countStoreReviews($storeId, $filters);
        $summary = $this->reviewModel->getStoreRatingSummary($storeId);

        return [
            'reviews'     => $reviews,
            'summary'     => $summary,
            'total_count' => $totalCount,
            'page'        => $page,
            'per_page'    => $perPage,
            'total_pages' => ceil($totalCount / $perPage),
            'filters'     => $filters
        ];
    }

    public function getStoreRatingSummary(int $storeId): array {
        return $this->reviewModel->getStoreRatingSummary($storeId);
    }

    /**
     * Get User Reviews & Pending items
     */
    public function getUserReviewData(int $userId): array {
        $myReviews = $this->reviewModel->getUserReviews($userId);
        $pendingItems = $this->reviewModel->getPendingReviewItemsForUser($userId);

        return [
            'my_reviews'    => $myReviews,
            'pending_items' => $pendingItems
        ];
    }

    public function getReviewDetail(int $id): ?array {
        return $this->reviewModel->findDetailById($id);
    }

    /**
     * Report Inappropriate Review via Central Report System
     */
    public function reportReview(int $userId, int $reviewId, string $reason, ?string $description = null): array {
        $review = $this->reviewModel->findById($reviewId);
        if (!$review || $review['status'] !== 'active') {
            return ['success' => false, 'message' => 'ไม่พบรีวิวที่ต้องการรายงาน'];
        }

        if ((int)$review['user_id'] === $userId) {
            return ['success' => false, 'message' => 'คุณไม่สามารถรายงานรีวิวของตนเองได้'];
        }

        $reason = trim($reason);
        if (empty($reason)) {
            return ['success' => false, 'message' => 'กรุณาระบุเหตุผลในการรายงาน'];
        }

        // Check duplicate report
        $existing = $this->reportModel->fetchOne(
            "SELECT id FROM `reports` WHERE `reporter_id` = :uid AND `report_type` = 'review' AND `target_id` = :tid AND `status` IN ('pending','reviewing') LIMIT 1",
            [':uid' => $userId, ':tid' => $reviewId]
        );

        if ($existing) {
            return ['success' => false, 'message' => 'คุณได้ส่งรายงานสำหรับรีวิวนี้แล้ว และกำลังอยู่ระหว่างการตรวจสอบ'];
        }

        $reportId = $this->reportModel->submitReport($userId, 'review', $reviewId, $reason, $description);

        $this->activityLog->record($userId, 'review_reported', 'review', $reviewId, "Reported review #{$reviewId}: {$reason}");

        return [
            'success'   => true,
            'message'   => 'ส่งรายงานเรียบร้อยแล้ว ทีมงานจะดำเนินการตรวจสอบโดยเร็ว',
            'report_id' => $reportId
        ];
    }

    /**
     * Helper to process, validate, and securely save uploaded images
     */
    private function processImageUploads(array $files, int $maxFiles): array {
        $uploadDir = __DIR__ . '/../../uploads/reviews/';
        if (!is_dir($uploadDir)) {
            @mkdir($uploadDir, 0755, true);
        }

        $paths = [];
        $fileCount = min(count($files['name']), $maxFiles);

        for ($i = 0; $i < $fileCount; $i++) {
            if ($files['error'][$i] === UPLOAD_ERR_NO_FILE) {
                continue;
            }

            if ($files['error'][$i] !== UPLOAD_ERR_OK) {
                return ['success' => false, 'message' => 'เกิดข้อผิดพลาดในการอัปโหลดไฟล์รูปภาพ'];
            }

            if ($files['size'][$i] > self::MAX_FILE_SIZE) {
                return ['success' => false, 'message' => 'ขนาดไฟล์รูปภาพต้องไม่เกิน 5MB ต่อรูป'];
            }

            $tmpPath = $files['tmp_name'][$i];
            $finfo = finfo_open(FILEINFO_MIME_TYPE);
            $mimeType = finfo_file($finfo, $tmpPath);
            finfo_close($finfo);

            if (!in_array($mimeType, self::ALLOWED_MIMES, true)) {
                return ['success' => false, 'message' => 'รองรับเฉพาะไฟล์รูปภาพประเภท JPG, PNG และ WebP เท่านั้น'];
            }

            $ext = strtolower(pathinfo($files['name'][$i], PATHINFO_EXTENSION));
            if (!in_array($ext, self::ALLOWED_EXTS, true)) {
                return ['success' => false, 'message' => 'นามสกุลไฟล์รูปภาพไม่ถูกต้อง'];
            }

            $safeFilename = 'rev_' . bin2hex(random_bytes(16)) . '.' . ($ext === 'jpeg' ? 'jpg' : $ext);
            $destination = $uploadDir . $safeFilename;

            if (move_uploaded_file($tmpPath, $destination)) {
                $paths[] = 'uploads/reviews/' . $safeFilename;
            } else {
                return ['success' => false, 'message' => 'ไม่สามารถบันทึกไฟล์รูปภาพได้'];
            }
        }

        return ['success' => true, 'paths' => $paths];
    }
}
