<?php

namespace App\Controllers;

use App\Models\ProductModel;
use App\Models\ProductImageModel;
use App\Models\BrandModel;
use App\Models\OfferModel;
use App\Models\OrderModel;
use App\Models\NotificationModel;
use App\Models\UserModel;
use App\Models\ReviewModel;
use App\Models\ContactViewModel;

class Buyer extends BaseController
{
    protected $productModel;
    protected $imageModel;
    protected $brandModel;
    protected $offerModel;
    protected $orderModel;
    protected $notificationModel;
    protected $userModel;
    protected $reviewModel;
    protected $contactViewModel;

    public function __construct()
    {
        $this->productModel = new ProductModel();
        $this->imageModel = new ProductImageModel();
        $this->brandModel = new BrandModel();
        $this->offerModel = new OfferModel();
        $this->orderModel = new OrderModel();
        $this->notificationModel = new NotificationModel();
        $this->userModel = new UserModel();
        $this->reviewModel = new ReviewModel();
        $this->contactViewModel = new ContactViewModel();
    }

    // B1 - Browse Products
    public function index()
    {
        $category = $this->request->getGet('category');
        $type = $this->request->getGet('type'); // buy or rent
        $search = $this->request->getGet('search');
        $gender = $this->request->getGet('gender');
        $minPrice = $this->request->getGet('min_price');
        $maxPrice = $this->request->getGet('max_price');
        $sort = $this->request->getGet('sort') ?? 'latest';

        $builder = $this->productModel
            ->select('products.*, product_images.image_path as primary_image, users.name as seller_name, users.seller_reliability_score, brands.brand_name')
            ->join('product_images', 'product_images.product_id = products.id AND product_images.is_primary = 1', 'left')
            ->join('users', 'users.id = products.seller_id')
            ->join('brands', 'brands.id = products.brand_id', 'left')
            ->where('products.status', 'approved');

        if ($category) {
            $builder->where('products.category', $category);
        }
        if ($type) {
            $builder->where('products.listing_type', $type);
        }
        if ($search) {
            $builder->groupStart()
                   ->like('products.title', $search)
                   ->orLike('products.description', $search)
                   ->orLike('products.category', $search)
                   ->groupEnd();
        }
        if ($gender) {
            $builder->where('products.gender', $gender);
        }
        if ($minPrice) {
            $builder->where('products.price >=', $minPrice);
        }
        if ($maxPrice) {
            $builder->where('products.price <=', $maxPrice);
        }

        // Sorting
        switch ($sort) {
            case 'price_low':
                $builder->orderBy('products.price', 'ASC');
                break;
            case 'price_high':
                $builder->orderBy('products.price', 'DESC');
                break;
            case 'popular':
                $builder->orderBy('users.seller_reliability_score', 'DESC');
                break;
            default:
                $builder->orderBy('products.created_at', 'DESC');
        }

        $products = $builder->paginate(12);

        $data = [
            'user' => session()->get('logged_in') ? $this->userModel->find(session()->get('user_id')) : null,
            'products' => $products,
            'pager' => $this->productModel->pager,
            'filters' => [
                'category' => $category,
                'type' => $type,
                'search' => $search,
                'gender' => $gender,
                'min_price' => $minPrice,
                'max_price' => $maxPrice,
                'sort' => $sort,
            ],
        ];

        return view('buyer/browse', $data);
    }

    // Product Details
    public function productDetails($productId)
    {
        $product = $this->productModel->find($productId);

        if (!$product || $product['status'] !== 'approved') {
            return redirect()->to('/buyer')->with('error', 'Product not found');
        }

        // Get all images
        $images = $this->imageModel->where('product_id', $productId)
                                   ->orderBy('display_order', 'ASC')
                                   ->findAll();

        // Get seller info
        $seller = $this->userModel->find($product['seller_id']);

        // Get brand info
        $brand = null;
        if ($product['brand_id']) {
            $brand = $this->brandModel->find($product['brand_id']);
        }

        // Get similar products
        $similarProducts = $this->productModel
            ->select('products.*, product_images.image_path as primary_image')
            ->join('product_images', 'product_images.product_id = products.id AND product_images.is_primary = 1', 'left')
            ->where('products.category', $product['category'])
            ->where('products.id !=', $productId)
            ->where('products.status', 'approved')
            ->limit(4)
            ->findAll();

        $data = [
            'user' => session()->get('logged_in') ? $this->userModel->find(session()->get('user_id')) : null,
            'product' => $product,
            'images' => $images,
            'seller' => $seller,
            'brand' => $brand,
            'similarProducts' => $similarProducts,
        ];

        return view('buyer/product_details', $data);
    }

    // Make Offer (B1, B17, B18)
    public function makeOffer()
    {
        if (!session()->get('logged_in')) {
            return $this->response->setJSON(['success' => false, 'message' => 'Please login first']);
        }

        $validation = \Config\Services::validation();

        $rules = [
            'product_id' => 'required|integer',
            'offer_type' => 'required|in_list[buy,rent]',
            'offered_price' => 'required|decimal',
        ];

        if ($this->request->getPost('offer_type') === 'rent') {
            $rules['rental_start_date'] = 'required|valid_date';
            $rules['rental_end_date'] = 'required|valid_date';
            $rules['deposit_amount'] = 'required|decimal';
        }

        if (!$this->validate($rules)) {
            return $this->response->setJSON([
                'success' => false,
                'errors' => $validation->getErrors()
            ]);
        }

        $productId = $this->request->getPost('product_id');
        $product = $this->productModel->find($productId);

        if (!$product) {
            return $this->response->setJSON(['success' => false, 'message' => 'Product not found']);
        }

        $userId = session()->get('user_id');

        // Check for date conflicts if rental (B16, B22)
        if ($this->request->getPost('offer_type') === 'rent') {
            $startDate = $this->request->getPost('rental_start_date');
            $endDate = $this->request->getPost('rental_end_date');

            $conflicts = $this->offerModel
                ->where('product_id', $productId)
                ->where('status', 'accepted')
                ->groupStart()
                    ->where('rental_start_date <=', $endDate)
                    ->where('rental_end_date >=', $startDate)
                ->groupEnd()
                ->countAllResults();

            if ($conflicts > 0) {
                return $this->response->setJSON([
                    'success' => false,
                    'message' => 'Product already booked for selected dates'
                ]);
            }
            // Enforce minimum rental duration of 3 days
            $s = strtotime($startDate);
            $e = strtotime($endDate);
            if ($e - $s < (3 * 24 * 60 * 60)) {
                return $this->response->setJSON([
                    'success' => false,
                    'message' => 'Rental period must be at least 3 days'
                ]);
            }
        }

        // Map posted field `offered_price` to DB column `offer_price`
        $offerData = [
            'product_id' => $productId,
            'buyer_id' => $userId,
            'seller_id' => $product['seller_id'],
            'offer_type' => $this->request->getPost('offer_type'),
            'offer_price' => $this->request->getPost('offered_price'),
            'message' => $this->request->getPost('message'),
            'status' => 'pending',
        ];

        if ($offerData['offer_type'] === 'rent') {
            $offerData['rental_start_date'] = $this->request->getPost('rental_start_date');
            $offerData['rental_end_date'] = $this->request->getPost('rental_end_date');
            $offerData['deposit_amount'] = $this->request->getPost('deposit_amount');
        }

        $offerId = $this->offerModel->insert($offerData);

        // Notify seller (B18)
        $this->notificationModel->insert([
            'user_id' => $product['seller_id'],
            'title' => 'New Offer Received',
            'message' => "You have a new {$offerData['offer_type']} offer for {$product['title']}",
            'type' => 'offer_received',
            'related_id' => $offerId,
        ]);

        return $this->response->setJSON([
            'success' => true,
            'message' => 'Offer sent successfully!',
            'offer_id' => $offerId
        ]);
    }

    // My Offers (B10, B23)
    public function myOffers()
    {
        if (!session()->get('logged_in')) {
            return redirect()->to('/login');
        }

        $userId = session()->get('user_id');
        $user = $this->userModel->find($userId);

        // Use model helper which provides aliases/defaults for backward compatibility
        $offers = $this->offerModel->getBuyerOffers($userId);

        $data = [
            'user' => $user,
            'offers' => $offers,
        ];

        return view('buyer/my_offers', $data);
    }

    // Transaction History (B10)
    public function transactions()
    {
        if (!session()->get('logged_in')) {
            return redirect()->to('/login');
        }

        $userId = session()->get('user_id');
        $user = $this->userModel->find($userId);

        // Get accepted offers (which will become orders in Phase 2)
        $transactions = $this->offerModel
            ->select('offers.*, products.title, products.listing_type, products.id as product_id, product_images.image_path as primary_image, users.name as seller_name')
            ->join('products', 'products.id = offers.product_id')
            ->join('users', 'users.id = offers.seller_id')
            ->join('product_images', 'product_images.product_id = products.id AND product_images.is_primary = 1', 'left')
            ->where('offers.buyer_id', $userId)
            ->where('offers.status', 'accepted')
            ->orderBy('offers.created_at', 'DESC')
            ->findAll();

        // Add order_number and final_price for display
        foreach ($transactions as &$transaction) {
            $transaction['order_number'] = 'FLX' . str_pad($transaction['id'], 6, '0', STR_PAD_LEFT);
            $transaction['final_price'] = $transaction['offered_price'];
            if ($transaction['listing_type'] === 'rent') {
                $transaction['final_price'] += $transaction['deposit_amount'] ?? 0;
            }
            $transaction['status'] = $transaction['status'] ?? 'pending';
        }

        $data = [
            'user' => $user,
            'transactions' => $transactions,
        ];

        return view('buyer/transactions', $data);
    }

    // Cancel Offer
    public function cancelOffer($offerId)
    {
        if (!session()->get('logged_in')) {
            return $this->response->setJSON(['success' => false, 'message' => 'Not logged in']);
        }

        $userId = session()->get('user_id');
        $offer = $this->offerModel->find($offerId);

        if (!$offer || $offer['buyer_id'] != $userId) {
            return $this->response->setJSON(['success' => false, 'message' => 'Invalid offer']);
        }

        if ($offer['status'] !== 'pending') {
            return $this->response->setJSON(['success' => false, 'message' => 'Cannot cancel this offer']);
        }

        $this->offerModel->delete($offerId);

        return $this->response->setJSON([
            'success' => true,
            'message' => 'Offer cancelled successfully'
        ]);
    }

    // B11-B15: Review System
    public function submitReview()
    {
        if (!session()->get('logged_in')) {
            return $this->response->setJSON(['success' => false, 'message' => 'Please login first']);
        }

        $validation = \Config\Services::validation();
        $rules = [
            'order_id' => 'required|integer',
            'rating' => 'required|integer|greater_than[0]|less_than[6]',
            'comment' => 'required|min_length[10]|max_length[500]',
        ];

        if (!$this->validate($rules)) {
            return $this->response->setJSON([
                'success' => false,
                'errors' => $validation->getErrors()
            ]);
        }

        $userId = session()->get('user_id');
        $orderId = $this->request->getPost('order_id');

        // Check if user can review
        if (!$this->reviewModel->canReview($orderId, $userId)) {
            return $this->response->setJSON([
                'success' => false,
                'message' => 'You cannot review this order'
            ]);
        }

        $order = $this->orderModel->find($orderId);
        $reviewedId = ($order['buyer_id'] == $userId) ? $order['seller_id'] : $order['buyer_id'];

        $reviewData = [
            'order_id' => $orderId,
            'reviewer_id' => $userId,
            'reviewed_id' => $reviewedId,
            'reviewer_type' => 'buyer',
            'rating' => $this->request->getPost('rating'),
            'comment' => $this->request->getPost('comment'),
        ];

        $this->reviewModel->insert($reviewData);

        // Notify seller
        $this->notificationModel->insert([
            'user_id' => $reviewedId,
            'title' => 'New Review Received',
            'message' => "You have received a {$reviewData['rating']}-star review",
            'type' => 'review_received',
            'related_id' => $orderId,
        ]);

        return $this->response->setJSON([
            'success' => true,
            'message' => 'Review submitted successfully!'
        ]);
    }

    // My Orders (for reviewing)
    public function myOrders()
    {
        if (!session()->get('logged_in')) {
            return redirect()->to('/login');
        }

        $userId = session()->get('user_id');
        $user = $this->userModel->find($userId);

        $orders = $this->orderModel
            ->select('orders.*, products.title as product_name, users.name as seller_name, product_images.image_path as primary_image')
            ->join('products', 'products.id = orders.product_id')
            ->join('users', 'users.id = orders.seller_id')
            ->join('product_images', 'product_images.product_id = products.id AND product_images.is_primary = 1', 'left')
            ->where('orders.buyer_id', $userId)
            ->orderBy('orders.created_at', 'DESC')
            ->findAll();

        // Check which orders can be reviewed
        foreach ($orders as &$order) {
            $order['can_review'] = $this->reviewModel->canReview($order['id'], $userId);
            $order['review'] = $this->reviewModel->where([
                'order_id' => $order['id'],
                'reviewer_id' => $userId
            ])->first();
        }

        $data = [
            'user' => $user,
            'orders' => $orders,
        ];

        return view('buyer/my_orders', $data);
    }

    // Buyer Subscriptions (B11)
    public function subscriptions()
    {
        if (!session()->get('logged_in')) {
            return redirect()->to('/login');
        }

        $userId = session()->get('user_id');
        $db = \Config\Database::connect();

        $subs = $db->table('user_subscriptions us')
               ->select('us.*, sp.package_name as package_name, sp.contact_limit, us.expires_at')
                   ->join('subscription_packages sp', 'sp.id = us.package_id', 'left')
                   ->where('us.user_id', $userId)
                   ->where('us.expires_at >=', date('Y-m-d'))
                   ->orderBy('us.expires_at', 'ASC')
                   ->get()
                   ->getResultArray();

        // For each subscription, compute contacts used from contact_views
        foreach ($subs as &$s) {
            $used = $db->table('contact_views')
                       ->where('user_id', $userId)
                       ->where('subscription_id', $s['id'])
                       ->countAllResults();
            $s['contacts_used'] = $used;
        }

        $data = [
            'user' => $this->userModel->find($userId),
            'subscriptions' => $subs,
        ];

        return view('buyer/subscriptions', $data);
    }

    // Self-Delivery Mode: View Seller Contact (IMPLEMENTED)
    public function viewSellerContact($productId)
    {
        if (!session()->get('logged_in')) {
            return $this->response->setJSON(['success' => false, 'message' => 'Please login first']);
        }

        $product = $this->productModel->find($productId);
        if (!$product) {
            return $this->response->setJSON(['success' => false, 'message' => 'Product not found']);
        }

        $buyerId = session()->get('user_id');
        $sellerId = $product['seller_id'];

        // Record contact view
        $this->contactViewModel->recordView($buyerId, $sellerId, $productId);

        // Get seller contact details
        $seller = $this->userModel->find($sellerId);

        return $this->response->setJSON([
            'success' => true,
            'seller' => [
                'name' => $seller['name'],
                'mobile' => $seller['mobile'],
                'address' => $seller['address'] ?? 'Not provided',
                'pin_code' => $seller['pin_code'] ?? '',
            ],
            'message' => 'Contact details revealed. You can rate this seller within 20 days of viewing contact.'
        ]);
    }

    // Self-Delivery Mode: Rate Seller (1 star only, within 20 days) (IMPLEMENTED)
    public function rateSelfDeliverySeller()
    {
        if (!session()->get('logged_in')) {
            return $this->response->setJSON(['success' => false, 'message' => 'Please login first']);
        }

        $validation = \Config\Services::validation();
        $rules = [
            'seller_id' => 'required|integer',
            'product_id' => 'required|integer',
        ];

        if (!$this->validate($rules)) {
            return $this->response->setJSON([
                'success' => false,
                'errors' => $validation->getErrors()
            ]);
        }

        $buyerId = session()->get('user_id');
        $sellerId = $this->request->getPost('seller_id');
        $productId = $this->request->getPost('product_id');

        // Check if buyer can rate seller (within 20 days of viewing contact)
        if (!$this->contactViewModel->canRateSeller($buyerId, $sellerId)) {
            return $this->response->setJSON([
                'success' => false,
                'message' => 'Cannot rate seller. Either contact was not viewed or 20-day window has expired.'
            ]);
        }

        // Check if already rated
        $existingReview = $this->reviewModel
            ->where('reviewer_id', $buyerId)
            ->where('reviewed_id', $sellerId)
            ->where('review_type', 'self_delivery')
            ->where('product_id', $productId)
            ->first();

        if ($existingReview) {
            return $this->response->setJSON([
                'success' => false,
                'message' => 'You have already rated this seller for self-delivery.'
            ]);
        }

        // Insert rating (always 1 star for self-delivery)
        $reviewData = [
            'reviewer_id' => $buyerId,
            'reviewed_id' => $sellerId,
            'product_id' => $productId,
            'reviewer_type' => 'buyer',
            'rating' => 1, // Always 1 star for self-delivery
            'comment' => $this->request->getPost('comment') ?: 'Self-delivery completed successfully',
            'review_type' => 'self_delivery',
        ];

        $this->reviewModel->insert($reviewData);

        // Update seller reliability score
        $seller = $this->userModel->find($sellerId);
        $newScore = ($seller['seller_reliability_score'] ?? 0) + 1;
        $this->userModel->update($sellerId, ['seller_reliability_score' => $newScore]);

        // Notify seller
        $this->notificationModel->insert([
            'user_id' => $sellerId,
            'title' => 'Self-Delivery Rating Received',
            'message' => 'You received a rating for self-delivery. Your reliability score increased!',
            'type' => 'rating_received',
            'related_id' => $productId,
        ]);

        return $this->response->setJSON([
            'success' => true,
            'message' => 'Rating submitted successfully!'
        ]);
    }

    // Request Fitting Alteration (IMPLEMENTED)
    public function requestFittingAlteration()
    {
        if (!session()->get('logged_in')) {
            return $this->response->setJSON(['success' => false, 'message' => 'Please login first']);
        }

        $validation = \Config\Services::validation();
        $rules = [
            'product_id' => 'required|integer',
            'alteration_details' => 'required|min_length[10]|max_length[500]',
        ];

        if (!$this->validate($rules)) {
            return $this->response->setJSON([
                'success' => false,
                'errors' => $validation->getErrors()
            ]);
        }

        $productId = $this->request->getPost('product_id');
        $product = $this->productModel->find($productId);

        if (!$product) {
            return $this->response->setJSON(['success' => false, 'message' => 'Product not found']);
        }

        // Check if alteration is allowed for this product
        if (!$product['allow_alter_fitting']) {
            return $this->response->setJSON([
                'success' => false,
                'message' => 'Fitting alteration is not allowed for this product.'
            ]);
        }

        $buyerId = session()->get('user_id');
        $sellerId = $product['seller_id'];

        // Save alteration request
        $db = \Config\Database::connect();
        $requestData = [
            'product_id' => $productId,
            'buyer_id' => $buyerId,
            'seller_id' => $sellerId,
            'alteration_details' => $this->request->getPost('alteration_details'),
            'status' => 'pending',
            'created_at' => date('Y-m-d H:i:s'),
        ];

        $db->table('fitting_alteration_requests')->insert($requestData);

        // Notify seller
        $this->notificationModel->insert([
            'user_id' => $sellerId,
            'title' => 'Fitting Alteration Request',
            'message' => "A buyer has requested fitting alteration for {$product['title']}",
            'type' => 'alteration_request',
            'related_id' => $productId,
        ]);

        return $this->response->setJSON([
            'success' => true,
            'message' => 'Fitting alteration request sent to seller!'
        ]);
    }

    // ORDER STATUS: Confirm delivery received (IMPLEMENTED)
    public function confirmDelivery($orderId)
    {
        if (!session()->get('logged_in')) {
            return $this->response->setJSON(['success' => false, 'message' => 'Please login first']);
        }

        $buyerId = session()->get('user_id');
        $order = $this->orderModel->find($orderId);

        if (!$order || $order['buyer_id'] != $buyerId) {
            return $this->response->setJSON(['success' => false, 'message' => 'Invalid order']);
        }

        if ($order['status'] !== 'dispatched') {
            return $this->response->setJSON(['success' => false, 'message' => 'Order cannot be confirmed']);
        }

        // Update order status to delivered
        $this->orderModel->updateOrderStatus($orderId, 'delivered', $buyerId, 'Buyer confirmed delivery');

        // Notify seller
        $this->notificationModel->insert([
            'user_id' => $order['seller_id'],
            'title' => 'Delivery Confirmed',
            'message' => "Buyer confirmed delivery of order #{$order['order_number']}",
            'type' => 'delivery_confirmed',
            'related_id' => $orderId,
        ]);

        return $this->response->setJSON([
            'success' => true,
            'message' => 'Delivery confirmed successfully! You can now review the seller.'
        ]);
    }

    // ORDER STATUS: Complete rental return (IMPLEMENTED)
    public function completeRentalReturn($orderId)
    {
        if (!session()->get('logged_in')) {
            return $this->response->setJSON(['success' => false, 'message' => 'Please login first']);
        }

        $buyerId = session()->get('user_id');
        $order = $this->orderModel->find($orderId);

        if (!$order || $order['buyer_id'] != $buyerId) {
            return $this->response->setJSON(['success' => false, 'message' => 'Invalid order']);
        }

        if ($order['order_type'] !== 'rent' || $order['status'] !== 'delivered') {
            return $this->response->setJSON(['success' => false, 'message' => 'Cannot complete rental return']);
        }

        // Update order status to returned
        $this->orderModel->updateOrderStatus($orderId, 'returned', $buyerId, 'Rental item returned by buyer');

        // Notify seller
        $this->notificationModel->insert([
            'user_id' => $order['seller_id'],
            'title' => 'Rental Returned',
            'message' => "Rental item for order #{$order['order_number']} has been returned",
            'type' => 'rental_returned',
            'related_id' => $orderId,
        ]);

        return $this->response->setJSON([
            'success' => true,
            'message' => 'Rental return completed. Seller will confirm receipt.'
        ]);
    }

    // ORDER STATUS: Cancel order (IMPLEMENTED)
    public function cancelOrder($orderId)
    {
        if (!session()->get('logged_in')) {
            return $this->response->setJSON(['success' => false, 'message' => 'Please login first']);
        }

        $buyerId = session()->get('user_id');
        $order = $this->orderModel->find($orderId);

        if (!$order || $order['buyer_id'] != $buyerId) {
            return $this->response->setJSON(['success' => false, 'message' => 'Invalid order']);
        }

        // Can only cancel if status is pending
        if ($order['status'] !== 'pending') {
            return $this->response->setJSON(['success' => false, 'message' => 'Order cannot be cancelled']);
        }

        $reason = $this->request->getPost('reason') ?: 'Buyer cancelled order';

        // Update order status to cancelled
        $this->orderModel->updateOrderStatus($orderId, 'cancelled', $buyerId, $reason);

        // Notify seller
        $this->notificationModel->insert([
            'user_id' => $order['seller_id'],
            'title' => 'Order Cancelled',
            'message' => "Order #{$order['order_number']} was cancelled by buyer",
            'type' => 'order_cancelled',
            'related_id' => $orderId,
        ]);

        return $this->response->setJSON([
            'success' => true,
            'message' => 'Order cancelled successfully'
        ]);
    }
}
