<?php

require_once APP_ROOT . '/models/Listing.php';
require_once APP_ROOT . '/models/ListingImage.php';
require_once APP_ROOT . '/models/ConditionOption.php';
require_once APP_ROOT . '/models/Collection.php';
require_once APP_ROOT . '/models/Item.php';
require_once APP_ROOT . '/models/Coin.php';
require_once APP_ROOT . '/models/Subcollection.php';
require_once APP_ROOT . '/models/User.php';
require_once APP_ROOT . '/helpers/Slug.php';

class MarketplaceController
{
    private Listing $listingModel;
    private ListingImage $imageModel;

    public function __construct()
    {
        $this->listingModel = new Listing();
        $this->imageModel = new ListingImage();
    }

    public function index(): void
    {
        $page = max(1, (int)($_GET['page'] ?? 1));
        $filters = $this->getFiltersFromRequest();

        $listings = $this->listingModel->listActive($filters, $page);
        $total = $this->listingModel->countActive($filters);
        $totalPages = max(1, (int)ceil($total / Listing::PER_PAGE));

        // Attach first image to each listing
        foreach ($listings as &$listing) {
            $firstImage = $this->imageModel->getFirstByListing((int)$listing['id']);
            $listing['first_image'] = $firstImage ? $firstImage['filename'] : null;
        }
        unset($listing);

        $conditionOptions = (new ConditionOption())->getAll();

        $pageTitle = Lang::get('marketplace') . ' | ' . Lang::get('app_name');
        $pageDescription = Lang::get('marketplace_meta_description');
        $pageUrl = APP_URL . '/marketplace';
        $pageKeywords = Lang::get('marketplace_keywords');

        require APP_ROOT . '/views/marketplace/index.php';
    }

    public function show(string $slug): void
    {
        $listing = $this->listingModel->findBySlug($slug);
        if (!$listing) {
            http_response_code(404);
            require APP_ROOT . '/views/pages/404.php';
            return;
        }

        $this->listingModel->incrementViews((int)$listing['id']);

        $images = $this->imageModel->getByListing((int)$listing['id']);
        $similar = $this->listingModel->similar((int)$listing['id'], 4);

        // Attach first image to similar listings
        foreach ($similar as &$sim) {
            $firstImage = $this->imageModel->getFirstByListing((int)$sim['id']);
            $sim['first_image'] = $firstImage ? $firstImage['filename'] : null;
        }
        unset($sim);

        // Check if bookmarked
        $isBookmarked = false;
        if (Session::isLoggedIn()) {
            require_once APP_ROOT . '/models/ListingBookmark.php';
            $bookmarkModel = new ListingBookmark();
            $isBookmarked = $bookmarkModel->isBookmarked(Session::getUserId(), (int)$listing['id']);
        }

        // User rating average
        require_once APP_ROOT . '/models/UserRating.php';
        $ratingModel = new UserRating();
        $sellerRating = $ratingModel->getAverageForUser((int)$listing['user_id']);

        $pageTitle = htmlspecialchars($listing['title']) . ' | ' . Lang::get('marketplace') . ' | ' . Lang::get('app_name');
        $pageDescription = mb_substr(strip_tags($listing['description'] ?? $listing['title']), 0, 160);
        $pageUrl = APP_URL . '/marketplace/' . $listing['slug'];
        $pageImage = !empty($images) ? APP_URL . '/uploads/listings/' . $images[0]['filename'] : DEFAULT_OG_IMAGE;

        require APP_ROOT . '/views/marketplace/show.php';
    }

    public function create(): void
    {
        if (!Session::isLoggedIn()) {
            header('Location: ' . APP_URL . '/login');
            exit;
        }

        $conditionOptions = (new ConditionOption())->getAll();
        $collections = (new Collection())->getAllByUser(Session::getUserId());

        // Optional pre-fill from existing collection item/coin
        $prefill = [];
        $sourceType = $_GET['source'] ?? '';
        $sourceId = (int)($_GET['id'] ?? 0);
        if ($sourceId > 0 && in_array($sourceType, ['banknote', 'coin'], true)) {
            $db = Database::getInstance();
            $userId = Session::getUserId();
            if ($sourceType === 'coin') {
                $stmt = $db->prepare(
                    'SELECT co.* FROM coins co
                     JOIN subcollections s ON co.subcollection_id = s.id
                     JOIN collections c ON s.collection_id = c.id
                     WHERE co.id = :id AND c.user_id = :user_id LIMIT 1'
                );
                $stmt->execute(['id' => $sourceId, 'user_id' => $userId]);
                $coin = $stmt->fetch();
                if ($coin) {
                    $matRaw = strtolower(trim((string)($coin['material'] ?? '')));
                    $matMap = ['silver' => 'silver', 'srebro' => 'silver', 'gold' => 'gold', 'zlato' => 'gold', 'copper' => 'copper', 'bakar' => 'copper', 'bronze' => 'bronze', 'bronza' => 'bronze', 'nickel' => 'nickel', 'nikl' => 'nickel'];
                    $material = $matMap[$matRaw] ?? '';
                    $prefill = [
                        'item_type'    => 'coin',
                        'title'        => trim(($coin['country'] ?? '') . ' ' . ($coin['nominal_value'] ?? '') . ' ' . ($coin['year_minted'] ?? '')),
                        'country'      => $coin['country'] ?? '',
                        'year'         => $coin['year_minted'] ?? '',
                        'material'     => $material,
                        'condition_id' => $coin['condition_id'] ?? null,
                        'description'  => $coin['note'] ?? ($coin['alloy_details'] ?? ''),
                    ];
                }
            } else {
                $stmt = $db->prepare(
                    'SELECT i.* FROM items i
                     JOIN subcollections s ON i.subcollection_id = s.id
                     JOIN collections c ON s.collection_id = c.id
                     WHERE i.id = :id AND c.user_id = :user_id LIMIT 1'
                );
                $stmt->execute(['id' => $sourceId, 'user_id' => $userId]);
                $item = $stmt->fetch();
                if ($item) {
                    $prefill = [
                        'item_type'   => 'banknote',
                        'title'       => trim(($item['country'] ?? '') . ' ' . ($item['nominal_value'] ?? '') . ' ' . ($item['issue_date'] ?? '')),
                        'country'     => $item['country'] ?? '',
                        'year'        => $item['issue_date'] ?? '',
                        'description' => $item['note'] ?? '',
                    ];
                }
            }
        }

        $pageTitle = Lang::get('create_listing') . ' | ' . Lang::get('marketplace') . ' | ' . Lang::get('app_name');
        $robotsMeta = 'noindex, nofollow';

        require APP_ROOT . '/views/marketplace/create.php';
    }

    public function store(): void
    {
        if (!Session::isLoggedIn()) {
            header('Location: ' . APP_URL . '/login');
            exit;
        }

        if (!Session::verifyCsrfToken($_POST['csrf_token'] ?? '')) {
            Session::flash('error', 'Invalid request.');
            header('Location: ' . APP_URL . '/marketplace/create');
            exit;
        }

        $title = trim($_POST['title'] ?? '');
        $description = trim($_POST['description'] ?? '');
        $listingType = $_POST['listing_type'] ?? 'sell';
        $itemType = $_POST['item_type'] ?? 'banknote';
        $country = trim($_POST['country'] ?? '');
        $year = trim($_POST['year'] ?? '');
        $conditionId = (int)($_POST['condition_id'] ?? 0);
        $material = trim($_POST['material'] ?? '');
        $askingPrice = trim($_POST['asking_price'] ?? '');
        $currency = $_POST['currency'] ?? 'EUR';
        $itemId = (int)($_POST['item_id'] ?? 0);

        // Validation
        $validator = new Validator();
        $validator->required('title', $title, Lang::get('title'));
        $validator->maxLength('title', $title, 200, Lang::get('title'));

        if (!in_array($listingType, ['buy', 'sell', 'trade'])) {
            $listingType = 'sell';
        }
        if (!in_array($itemType, ['banknote', 'coin', 'other'])) {
            $itemType = 'banknote';
        }
        if (!in_array($currency, ['EUR', 'USD', 'RSD', 'GBP', 'CHF'])) {
            $currency = 'EUR';
        }

        if ($validator->fails()) {
            Session::flash('error', $validator->firstError());
            header('Location: ' . APP_URL . '/marketplace/create');
            exit;
        }

        $data = [
            'user_id'      => Session::getUserId(),
            'title'        => $title,
            'description'  => $description ?: null,
            'listing_type' => $listingType,
            'item_type'    => $itemType,
            'item_id'      => $itemId ?: null,
            'country'      => $country ?: null,
            'year'         => $year ?: null,
            'condition_id' => $conditionId ?: null,
            'material'     => $material ?: null,
            'asking_price' => ($askingPrice !== '' && is_numeric($askingPrice)) ? (float)$askingPrice : null,
            'currency'     => $currency,
        ];

        $listingId = $this->listingModel->create($data);

        // Handle image uploads (up to 4)
        if (!empty($_FILES['images'])) {
            $this->handleImageUploads($listingId, $_FILES['images']);
        }

        Session::flash('success', Lang::get('listing_created'));
        header('Location: ' . APP_URL . '/marketplace/my-listings');
        exit;
    }

    public function edit(string $slug): void
    {
        if (!Session::isLoggedIn()) {
            header('Location: ' . APP_URL . '/login');
            exit;
        }

        $listing = $this->listingModel->findBySlug($slug);
        if (!$listing || (int)$listing['user_id'] !== Session::getUserId()) {
            http_response_code(404);
            require APP_ROOT . '/views/pages/404.php';
            return;
        }

        $images = $this->imageModel->getByListing((int)$listing['id']);
        $conditionOptions = (new ConditionOption())->getAll();

        $pageTitle = Lang::get('edit_listing') . ' | ' . Lang::get('marketplace') . ' | ' . Lang::get('app_name');
        $robotsMeta = 'noindex, nofollow';

        require APP_ROOT . '/views/marketplace/edit.php';
    }

    public function update(string $id): void
    {
        if (!Session::isLoggedIn()) {
            header('Location: ' . APP_URL . '/login');
            exit;
        }

        $listing = $this->listingModel->findById((int)$id);
        if (!$listing || (int)$listing['user_id'] !== Session::getUserId()) {
            http_response_code(404);
            require APP_ROOT . '/views/pages/404.php';
            return;
        }

        if (!Session::verifyCsrfToken($_POST['csrf_token'] ?? '')) {
            Session::flash('error', 'Invalid request.');
            header('Location: ' . APP_URL . '/marketplace/' . $listing['slug'] . '/edit');
            exit;
        }

        $title = trim($_POST['title'] ?? '');
        $description = trim($_POST['description'] ?? '');
        $listingType = $_POST['listing_type'] ?? 'sell';
        $itemType = $_POST['item_type'] ?? 'banknote';
        $status = $_POST['status'] ?? 'active';
        $country = trim($_POST['country'] ?? '');
        $year = trim($_POST['year'] ?? '');
        $conditionId = (int)($_POST['condition_id'] ?? 0);
        $material = trim($_POST['material'] ?? '');
        $askingPrice = trim($_POST['asking_price'] ?? '');
        $currency = $_POST['currency'] ?? 'EUR';

        $validator = new Validator();
        $validator->required('title', $title, Lang::get('title'));

        if ($validator->fails()) {
            Session::flash('error', $validator->firstError());
            header('Location: ' . APP_URL . '/marketplace/' . $listing['slug'] . '/edit');
            exit;
        }

        if (!in_array($listingType, ['buy', 'sell', 'trade'])) $listingType = 'sell';
        if (!in_array($itemType, ['banknote', 'coin', 'other'])) $itemType = 'banknote';
        if (!in_array($status, ['active', 'closed', 'sold'])) $status = 'active';
        if (!in_array($currency, ['EUR', 'USD', 'RSD', 'GBP', 'CHF'])) $currency = 'EUR';

        $this->listingModel->update((int)$id, [
            'title'        => $title,
            'description'  => $description ?: null,
            'listing_type' => $listingType,
            'item_type'    => $itemType,
            'status'       => $status,
            'country'      => $country ?: null,
            'year'         => $year ?: null,
            'condition_id' => $conditionId ?: null,
            'material'     => $material ?: null,
            'asking_price' => ($askingPrice !== '' && is_numeric($askingPrice)) ? (float)$askingPrice : null,
            'currency'     => $currency,
        ]);

        // Handle delete existing images
        $deleteImages = $_POST['delete_images'] ?? [];
        foreach ($deleteImages as $imgId) {
            $this->imageModel->delete((int)$imgId);
        }

        // Handle new image uploads
        if (!empty($_FILES['images'])) {
            $currentCount = $this->imageModel->countByListing((int)$id);
            $this->handleImageUploads((int)$id, $_FILES['images'], $currentCount);
        }

        Session::flash('success', Lang::get('listing_updated'));
        header('Location: ' . APP_URL . '/marketplace/' . $listing['slug']);
        exit;
    }

    public function delete(string $id): void
    {
        if (!Session::isLoggedIn()) {
            header('Location: ' . APP_URL . '/login');
            exit;
        }

        $listing = $this->listingModel->findById((int)$id);
        if (!$listing || (int)$listing['user_id'] !== Session::getUserId()) {
            http_response_code(404);
            require APP_ROOT . '/views/pages/404.php';
            return;
        }

        // Delete images
        $this->imageModel->deleteByListing((int)$id);
        $this->listingModel->delete((int)$id);

        Session::flash('success', Lang::get('listing_deleted'));
        header('Location: ' . APP_URL . '/marketplace/my-listings');
        exit;
    }

    public function close(string $id): void
    {
        if (!Session::isLoggedIn()) {
            header('Location: ' . APP_URL . '/login');
            exit;
        }

        $listing = $this->listingModel->findById((int)$id);
        if (!$listing || (int)$listing['user_id'] !== Session::getUserId()) {
            http_response_code(404);
            require APP_ROOT . '/views/pages/404.php';
            return;
        }

        // Only allow 'closed' here; selling goes through the dedicated soldForm/markSold flow
        $status = $_GET['status'] ?? 'closed';
        if ($status === 'sold') {
            header('Location: ' . APP_URL . '/marketplace/' . $id . '/sold');
            exit;
        }
        if ($status !== 'closed') $status = 'closed';

        $this->listingModel->updateStatus((int)$id, $status);

        Session::flash('success', Lang::get('listing_closed'));
        header('Location: ' . APP_URL . '/marketplace/my-listings');
        exit;
    }

    /**
     * GET /marketplace/{id}/sold — show buyer-selection form before marking sold.
     */
    public function soldForm(string $id): void
    {
        if (!Session::isLoggedIn()) {
            header('Location: ' . APP_URL . '/login');
            exit;
        }

        $listing = $this->listingModel->findById((int)$id);
        if (!$listing || (int)$listing['user_id'] !== Session::getUserId()) {
            http_response_code(404);
            require APP_ROOT . '/views/pages/404.php';
            return;
        }

        if ($listing['status'] !== 'active') {
            Session::flash('error', Lang::get('listing_not_active'));
            header('Location: ' . APP_URL . '/marketplace/my-listings');
            exit;
        }

        require_once APP_ROOT . '/models/Message.php';
        $messageModel = new Message();
        $candidates = $messageModel->getCounterpartiesForListing((int)$id, Session::getUserId());

        $pageTitle = Lang::get('mark_as_sold_title') . ' | ' . Lang::get('marketplace') . ' | ' . Lang::get('app_name');
        require APP_ROOT . '/views/marketplace/mark-sold.php';
    }

    /**
     * POST /marketplace/{id}/sold — persist the sale and notify both parties.
     */
    public function markSold(string $id): void
    {
        if (!Session::isLoggedIn()) {
            header('Location: ' . APP_URL . '/login');
            exit;
        }
        if (!Session::verifyCsrfToken($_POST['csrf_token'] ?? '')) {
            Session::flash('error', 'Invalid request.');
            header('Location: ' . APP_URL . '/marketplace/' . $id . '/sold');
            exit;
        }

        $listing = $this->listingModel->findById((int)$id);
        if (!$listing || (int)$listing['user_id'] !== Session::getUserId()) {
            http_response_code(404);
            require APP_ROOT . '/views/pages/404.php';
            return;
        }
        if ($listing['status'] !== 'active') {
            Session::flash('error', Lang::get('listing_not_active'));
            header('Location: ' . APP_URL . '/marketplace/my-listings');
            exit;
        }

        $sellerId = Session::getUserId();
        $buyerChoice = $_POST['buyer_id'] ?? '';
        $buyerId = null;

        if ($buyerChoice !== '' && $buyerChoice !== 'other') {
            $candidateId = (int)$buyerChoice;
            // Verify candidate is actually a counterparty for this listing
            require_once APP_ROOT . '/models/Message.php';
            $messageModel = new Message();
            $candidates = $messageModel->getCounterpartiesForListing((int)$id, $sellerId);
            $valid = false;
            foreach ($candidates as $c) {
                if ((int)$c['id'] === $candidateId) { $valid = true; break; }
            }
            if (!$valid) {
                Session::flash('error', Lang::get('invalid_buyer_selection'));
                header('Location: ' . APP_URL . '/marketplace/' . $id . '/sold');
                exit;
            }
            $buyerId = $candidateId;
        }

        $this->listingModel->markSold((int)$id, $buyerId);

        // Send system messages to both parties so the rating CTA shows up in their inbox
        if ($buyerId !== null) {
            require_once APP_ROOT . '/models/Message.php';
            $messageModel = $messageModel ?? new Message();
            $listingTitle = $listing['title'];
            $rateUrlForBuyer  = APP_URL . '/marketplace/' . $id . '/rate/' . $sellerId;
            $rateUrlForSeller = APP_URL . '/marketplace/' . $id . '/rate/' . $buyerId;

            $messageModel->create([
                'sender_id'    => $sellerId,
                'recipient_id' => $buyerId,
                'listing_id'   => (int)$id,
                'subject'      => '[SYSTEM] ' . Lang::get('system_message_sold_subject'),
                'body'         => sprintf(Lang::get('system_message_sold_buyer'), $listingTitle, $rateUrlForBuyer),
            ]);
            $messageModel->create([
                'sender_id'    => $buyerId,
                'recipient_id' => $sellerId,
                'listing_id'   => (int)$id,
                'subject'      => '[SYSTEM] ' . Lang::get('system_message_sold_subject'),
                'body'         => sprintf(Lang::get('system_message_sold_seller'), $listingTitle, $rateUrlForSeller),
            ]);

            Session::flash('success', Lang::get('listing_marked_sold_with_buyer'));
        } else {
            Session::flash('success', Lang::get('listing_marked_sold_external'));
        }

        header('Location: ' . APP_URL . '/marketplace/' . $listing['slug']);
        exit;
    }

    /**
     * GET /marketplace/{id}/rate/{userId} — render rating form.
     */
    public function rateForm(string $id, string $userId): void
    {
        if (!Session::isLoggedIn()) {
            header('Location: ' . APP_URL . '/login');
            exit;
        }

        $listing = $this->listingModel->findById((int)$id);
        if (!$listing) {
            http_response_code(404);
            require APP_ROOT . '/views/pages/404.php';
            return;
        }

        require_once APP_ROOT . '/models/UserRating.php';
        require_once APP_ROOT . '/models/User.php';
        $ratingModel = new UserRating();
        $raterId = Session::getUserId();
        $rateeId = (int)$userId;

        // If already rated, show the existing rating instead of the form
        $existing = $ratingModel->getRatingByRaterForListing($raterId, (int)$id);

        $check = $ratingModel->canRate($raterId, $rateeId, $listing);
        if (!$check['allowed'] && !$existing) {
            Session::flash('error', Lang::get('rating_not_allowed_' . $check['reason']));
            header('Location: ' . APP_URL . '/marketplace/' . $listing['slug']);
            exit;
        }

        $userModel = new User();
        $ratee = $userModel->findById($rateeId);
        if (!$ratee) {
            http_response_code(404);
            require APP_ROOT . '/views/pages/404.php';
            return;
        }

        $firstImage = $this->imageModel->getFirstByListing((int)$id);
        $listingImage = $firstImage ? APP_URL . '/uploads/listings/' . $firstImage['filename'] : null;

        $pageTitle = Lang::get('rate_user_title') . ' | ' . Lang::get('marketplace') . ' | ' . Lang::get('app_name');
        require APP_ROOT . '/views/marketplace/rate.php';
    }

    /**
     * POST /marketplace/{id}/rate/{userId} — persist rating after canRate check.
     */
    public function submitRating(string $id, string $userId): void
    {
        if (!Session::isLoggedIn()) {
            header('Location: ' . APP_URL . '/login');
            exit;
        }
        if (!Session::verifyCsrfToken($_POST['csrf_token'] ?? '')) {
            Session::flash('error', 'Invalid request.');
            header('Location: ' . APP_URL . '/marketplace/' . $id . '/rate/' . $userId);
            exit;
        }

        $listing = $this->listingModel->findById((int)$id);
        if (!$listing) {
            http_response_code(404);
            require APP_ROOT . '/views/pages/404.php';
            return;
        }

        require_once APP_ROOT . '/models/UserRating.php';
        $ratingModel = new UserRating();
        $raterId = Session::getUserId();
        $rateeId = (int)$userId;

        $check = $ratingModel->canRate($raterId, $rateeId, $listing);
        if (!$check['allowed']) {
            Session::flash('error', Lang::get('rating_not_allowed_' . $check['reason']));
            header('Location: ' . APP_URL . '/marketplace/' . $listing['slug']);
            exit;
        }

        $rating = (int)($_POST['rating'] ?? 0);
        $comment = trim((string)($_POST['comment'] ?? ''));
        if ($rating < 1 || $rating > 5) {
            Session::flash('error', Lang::get('invalid_rating_value'));
            header('Location: ' . APP_URL . '/marketplace/' . $id . '/rate/' . $userId);
            exit;
        }
        if (mb_strlen($comment) > 1000) {
            $comment = mb_substr($comment, 0, 1000);
        }

        $ratingModel->create([
            'rater_id'      => $raterId,
            'rated_user_id' => $rateeId,
            'listing_id'    => (int)$id,
            'rating'        => $rating,
            'comment'       => $comment !== '' ? $comment : null,
        ]);

        Session::flash('success', Lang::get('rating_submitted_success'));
        header('Location: ' . APP_URL . '/marketplace/user/' . $rateeId);
        exit;
    }

    public function myListings(): void
    {
        if (!Session::isLoggedIn()) {
            header('Location: ' . APP_URL . '/login');
            exit;
        }

        $listings = $this->listingModel->getByUser(Session::getUserId());

        // Attach first image
        foreach ($listings as &$listing) {
            $firstImage = $this->imageModel->getFirstByListing((int)$listing['id']);
            $listing['first_image'] = $firstImage ? $firstImage['filename'] : null;
        }
        unset($listing);

        $pageTitle = Lang::get('my_listings') . ' | ' . Lang::get('marketplace') . ' | ' . Lang::get('app_name');
        $robotsMeta = 'noindex, nofollow';

        require APP_ROOT . '/views/marketplace/my-listings.php';
    }

    public function apiUserItems(): void
    {
        if (!Session::isLoggedIn()) {
            http_response_code(401);
            echo json_encode(['success' => false]);
            exit;
        }

        $userId = Session::getUserId();
        $type = $_GET['type'] ?? 'banknote';
        $results = [];

        $collectionModel = new Collection();
        $collections = $collectionModel->getAllByUser($userId);

        foreach ($collections as $col) {
            if ($type === 'coin' && ($col['type'] ?? 'banknote') !== 'coin') continue;
            if ($type === 'banknote' && ($col['type'] ?? 'banknote') !== 'banknote') continue;

            $subcollectionModel = new Subcollection();
            $subcollections = $subcollectionModel->getAllByCollection((int)$col['id']);

            foreach ($subcollections as $sub) {
                if ($type === 'coin') {
                    $coinModel = new Coin();
                    $coins = $coinModel->getAllBySubcollection((int)$sub['id']);
                    foreach ($coins as $coin) {
                        $results[] = [
                            'id'       => $coin['id'],
                            'type'     => 'coin',
                            'title'    => ($coin['country'] ?? '') . ' ' . ($coin['year_minted'] ?? '') . ' ' . ($coin['nominal_value'] ?? ''),
                            'country'  => $coin['country'] ?? '',
                            'year'     => $coin['year_minted'] ?? '',
                            'material' => $coin['material'] ?? '',
                            'image'    => $coin['image_obverse'] ?? '',
                            'collection' => $col['name'] . ' / ' . $sub['name'],
                        ];
                    }
                } else {
                    $itemModel = new Item();
                    $items = $itemModel->getAllBySubcollection((int)$sub['id']);
                    foreach ($items as $item) {
                        $results[] = [
                            'id'       => $item['id'],
                            'type'     => 'banknote',
                            'title'    => ($item['country'] ?? '') . ' ' . ($item['issue_date'] ?? '') . ' ' . ($item['nominal_value'] ?? ''),
                            'country'  => $item['country'] ?? '',
                            'year'     => $item['issue_date'] ?? '',
                            'material' => '',
                            'image'    => $item['image_obverse'] ?? '',
                            'collection' => $col['name'] . ' / ' . $sub['name'],
                        ];
                    }
                }
            }
        }

        header('Content-Type: application/json');
        echo json_encode(['success' => true, 'items' => $results]);
        exit;
    }

    public function apiBookmarkAdd(): void
    {
        if (!Session::isLoggedIn()) {
            http_response_code(401);
            echo json_encode(['success' => false]);
            exit;
        }
        if (!Session::verifyCsrfToken($_POST['csrf_token'] ?? '')) {
            http_response_code(403);
            echo json_encode(['success' => false]);
            exit;
        }
        $listingId = (int)($_POST['listing_id'] ?? 0);
        if ($listingId <= 0) {
            http_response_code(400);
            echo json_encode(['success' => false]);
            exit;
        }
        require_once APP_ROOT . '/models/ListingBookmark.php';
        $bm = new ListingBookmark();
        $bm->add(Session::getUserId(), $listingId);
        header('Content-Type: application/json');
        echo json_encode(['success' => true, 'bookmarked_text' => Lang::get('bookmarked')]);
        exit;
    }

    public function bookmark(string $id = ''): void
    {
        // Clear any previous output
        if (ob_get_length()) ob_clean();

        // Set JSON header first
        header('Content-Type: application/json');

        try {
            if (!Session::isLoggedIn()) {
                http_response_code(401);
                echo json_encode(['success' => false, 'error' => 'Unauthorized']);
                exit;
            }

            if (!Session::verifyCsrfToken($_POST['csrf_token'] ?? '')) {
                http_response_code(403);
                echo json_encode(['success' => false, 'error' => 'Invalid CSRF token']);
                exit;
            }

            $listingId = (int)($_POST['listing_id'] ?? $id);
            if ($listingId === 0) {
                http_response_code(400);
                echo json_encode(['success' => false, 'error' => 'Invalid listing ID']);
                exit;
            }

            $listing = $this->listingModel->findById($listingId);
            if (!$listing) {
                http_response_code(404);
                echo json_encode(['success' => false, 'error' => 'Listing not found']);
                exit;
            }

            if ((int)$listing['user_id'] === Session::getUserId()) {
                http_response_code(403);
                echo json_encode(['success' => false, 'error' => 'Cannot bookmark your own listing']);
                exit;
            }

            require_once APP_ROOT . '/models/ListingBookmark.php';
            $bm = new ListingBookmark();
            
            // Check if already bookmarked
            $isBookmarked = $bm->isBookmarked(Session::getUserId(), $listingId);
            
            if ($isBookmarked) {
                // Remove bookmark
                $result = $bm->remove(Session::getUserId(), $listingId);
                if ($result) {
                    echo json_encode(['success' => true, 'bookmark_text' => Lang::get('bookmark')]);
                } else {
                    echo json_encode(['success' => false, 'error' => 'Failed to remove bookmark']);
                }
            } else {
                // Add bookmark
                $result = $bm->add(Session::getUserId(), $listingId);
                if ($result) {
                    echo json_encode(['success' => true, 'bookmarked_text' => Lang::get('bookmarked')]);
                } else {
                    echo json_encode(['success' => false, 'error' => 'Failed to add bookmark']);
                }
            }
        } catch (Throwable $e) {
            error_log('Marketplace bookmark error: ' . $e->getMessage());
            http_response_code(500);
            echo json_encode(['success' => false, 'error' => 'Server error']);
        }
        exit;
    }

    public function apiBookmarkRemove(): void
    {
        if (!Session::isLoggedIn()) {
            http_response_code(401);
            echo json_encode(['success' => false]);
            exit;
        }
        if (!Session::verifyCsrfToken($_POST['csrf_token'] ?? '')) {
            http_response_code(403);
            echo json_encode(['success' => false]);
            exit;
        }
        $listingId = (int)($_POST['listing_id'] ?? 0);
        require_once APP_ROOT . '/models/ListingBookmark.php';
        $bm = new ListingBookmark();
        $bm->remove(Session::getUserId(), $listingId);
        header('Content-Type: application/json');
        echo json_encode(['success' => true, 'bookmark_text' => Lang::get('bookmark')]);
        exit;
    }

    public function bookmarks(): void
    {
        if (!Session::isLoggedIn()) {
            header('Location: ' . APP_URL . '/login');
            exit;
        }
        require_once APP_ROOT . '/models/ListingBookmark.php';
        $bm = new ListingBookmark();
        $listings = $bm->getByUser(Session::getUserId());

        foreach ($listings as &$listing) {
            $firstImage = $this->imageModel->getFirstByListing((int)$listing['id']);
            $listing['first_image'] = $firstImage ? $firstImage['filename'] : null;
        }
        unset($listing);

        $pageTitle = Lang::get('bookmarks') . ' | ' . Lang::get('marketplace') . ' | ' . Lang::get('app_name');
        $robotsMeta = 'noindex, nofollow';

        require APP_ROOT . '/views/marketplace/bookmarks.php';
    }

    public function savedSearches(): void
    {
        if (!Session::isLoggedIn()) {
            header('Location: ' . APP_URL . '/login');
            exit;
        }
        require_once APP_ROOT . '/models/SavedSearch.php';
        
        $searchQuery = $_GET['search'] ?? '';
        $savedSearches = (new SavedSearch())->searchByUser(Session::getUserId(), $searchQuery);
        
        $pageTitle = Lang::get('saved_searches') . ' | ' . Lang::get('marketplace') . ' | ' . Lang::get('app_name');
        $robotsMeta = 'noindex, nofollow';
        require APP_ROOT . '/views/marketplace/saved-searches.php';
    }

    public function apiSavedSearchStore(): void
    {
        header('Content-Type: application/json');
        if (!Session::isLoggedIn()) {
            http_response_code(401);
            echo json_encode(['success' => false, 'message' => 'Not authenticated']);
            exit;
        }
        if (!Session::verifyCsrfToken($_POST['csrf_token'] ?? '')) {
            http_response_code(403);
            echo json_encode(['success' => false, 'message' => 'Invalid CSRF token']);
            exit;
        }

        $name = trim($_POST['name'] ?? '');
        if ($name === '') {
            http_response_code(400);
            echo json_encode(['success' => false, 'message' => 'Name is required']);
            exit;
        }

        // Whitelist filter keys to avoid storing arbitrary input
        $allowed = ['listing_type', 'item_type', 'country', 'year', 'year_from', 'year_to', 'condition_id', 'material', 'price_from', 'price_to', 'currency', 'sort', 'q'];
        $rawFilters = isset($_POST['filters']) && is_array($_POST['filters']) ? $_POST['filters'] : [];
        $filters = [];
        foreach ($allowed as $key) {
            if (!empty($rawFilters[$key])) {
                $filters[$key] = is_string($rawFilters[$key]) ? trim($rawFilters[$key]) : $rawFilters[$key];
            }
        }

        require_once APP_ROOT . '/models/SavedSearch.php';
        $model = new SavedSearch();

        // Hard cap: 20 saved searches per user
        if ($model->countByUser(Session::getUserId()) >= 20) {
            http_response_code(400);
            echo json_encode(['success' => false, 'message' => Lang::get('saved_search_limit_reached')]);
            exit;
        }

        $id = $model->create(Session::getUserId(), $name, $filters);
        echo json_encode(['success' => true, 'id' => $id]);
        exit;
    }

    public function apiSavedSearchDelete(): void
    {
        header('Content-Type: application/json');
        if (!Session::isLoggedIn()) {
            http_response_code(401);
            echo json_encode(['success' => false]);
            exit;
        }
        if (!Session::verifyCsrfToken($_POST['csrf_token'] ?? '')) {
            http_response_code(403);
            echo json_encode(['success' => false]);
            exit;
        }
        $id = (int)($_POST['id'] ?? 0);
        if ($id <= 0) {
            http_response_code(400);
            echo json_encode(['success' => false]);
            exit;
        }
        require_once APP_ROOT . '/models/SavedSearch.php';
        (new SavedSearch())->delete($id, Session::getUserId());
        echo json_encode(['success' => true]);
        exit;
    }

    public function userProfile(string $id): void
    {
        $userModel = new User();
        $user = $userModel->findById((int)$id);
        if (!$user) {
            http_response_code(404);
            require APP_ROOT . '/views/pages/404.php';
            return;
        }

        $activeListings = $this->listingModel->getActiveByUser((int)$id, 20);
        foreach ($activeListings as &$listing) {
            $firstImage = $this->imageModel->getFirstByListing((int)$listing['id']);
            $listing['first_image'] = $firstImage ? $firstImage['filename'] : null;
        }
        unset($listing);

        require_once APP_ROOT . '/models/UserRating.php';
        $ratingModel = new UserRating();
        $sellerRating = $ratingModel->getAverageForUser((int)$id);
        $reviews = $ratingModel->getByUser((int)$id);

        $pageTitle = ($user['display_name'] ?: $user['username']) . ' | ' . Lang::get('marketplace') . ' | ' . Lang::get('app_name');
        $pageDescription = Lang::get('marketplace') . ' - ' . ($user['display_name'] ?: $user['username']);
        $pageUrl = APP_URL . '/marketplace/user/' . $id;

        require APP_ROOT . '/views/marketplace/user-profile.php';
    }

    public function reportForm(string $id): void
    {
        if (!Session::isLoggedIn()) {
            header('Location: ' . APP_URL . '/login');
            exit;
        }
        $listing = $this->listingModel->findById((int)$id);
        if (!$listing) {
            http_response_code(404);
            require APP_ROOT . '/views/pages/404.php';
            return;
        }
        $pageTitle = Lang::get('report_listing') . ' | ' . Lang::get('app_name');
        $robotsMeta = 'noindex, nofollow';
        require APP_ROOT . '/views/marketplace/report.php';
    }

    public function report(string $id): void
    {
        if (!Session::isLoggedIn()) {
            header('Location: ' . APP_URL . '/login');
            exit;
        }
        if (!Session::verifyCsrfToken($_POST['csrf_token'] ?? '')) {
            Session::flash('error', 'Invalid request.');
            header('Location: ' . APP_URL . '/marketplace');
            exit;
        }
        $listing = $this->listingModel->findById((int)$id);
        if (!$listing) {
            http_response_code(404);
            require APP_ROOT . '/views/pages/404.php';
            return;
        }

        $reason = $_POST['reason'] ?? 'other';
        $description = trim($_POST['description'] ?? '');
        if (!in_array($reason, ['scam', 'inappropriate', 'spam', 'other'])) $reason = 'other';

        $db = Database::getInstance();
        $stmt = $db->prepare('INSERT INTO listing_reports (listing_id, reporter_id, reason, description) VALUES (:listing_id, :reporter_id, :reason, :description)');
        $stmt->execute([
            'listing_id'  => (int)$id,
            'reporter_id' => Session::getUserId(),
            'reason'      => $reason,
            'description' => $description ?: null,
        ]);

        Session::flash('success', Lang::get('report_submitted'));
        header('Location: ' . APP_URL . '/marketplace/' . $listing['slug']);
        exit;
    }

    private function handleImageUploads(int $listingId, array $files, int $existingCount = 0): void
    {
        error_log("Marketplace: handleImageUploads called for listing {$listingId}");
        error_log("Marketplace: FILES data: " . print_r($files, true));
        
        if (!is_dir(UPLOAD_LISTINGS_PATH)) {
            error_log("Marketplace: Creating directory: " . UPLOAD_LISTINGS_PATH);
            mkdir(UPLOAD_LISTINGS_PATH, 0755, true);
        }
        if (!is_dir(UPLOAD_LISTINGS_THUMBS_PATH)) {
            error_log("Marketplace: Creating thumbs directory: " . UPLOAD_LISTINGS_THUMBS_PATH);
            mkdir(UPLOAD_LISTINGS_THUMBS_PATH, 0755, true);
        }

        error_log("Marketplace: Upload directory exists: " . (is_dir(UPLOAD_LISTINGS_PATH) ? 'YES' : 'NO'));
        error_log("Marketplace: Upload directory writable: " . (is_writable(UPLOAD_LISTINGS_PATH) ? 'YES' : 'NO'));

        $maxImages = 4 - $existingCount;
        $uploaded = 0;

        for ($i = 0; $i < count($files['name'] ?? []); $i++) {
            if ($uploaded >= $maxImages) break;
            if (empty($files['name'][$i]) || $files['error'][$i] !== UPLOAD_ERR_OK) {
                error_log("Marketplace: Skipping file {$i} - name: '{$files['name'][$i]}', error: {$files['error'][$i]}");
                continue;
            }

            $file = [
                'name'     => $files['name'][$i],
                'type'     => $files['type'][$i],
                'tmp_name' => $files['tmp_name'][$i],
                'error'    => $files['error'][$i],
                'size'     => $files['size'][$i],
            ];

            error_log("Marketplace: Processing file: {$file['name']}, type: {$file['type']}, size: {$file['size']}");
            
            $result = FileUpload::upload($file, UPLOAD_LISTINGS_PATH, ALLOWED_IMAGE_TYPES);
            
            if ($result['success']) {
                error_log("Marketplace: File uploaded successfully: {$result['filename']}");
                error_log("Marketplace: File path: {$result['filepath']}");
                
                // Create thumbnail
                $thumbPath = FileUpload::getThumbnailPath($result['filepath'], UPLOAD_LISTINGS_THUMBS_PATH);
                error_log("Marketplace: Creating thumbnail at: {$thumbPath}");
                
                $thumbResult = FileUpload::createThumbnail($result['filepath'], $thumbPath, 400, 300, 80);
                if ($thumbResult['success']) {
                    error_log("Marketplace: Thumbnail created successfully at: {$thumbPath}");
                    // Verify thumbnail was actually created
                    if (file_exists($thumbPath)) {
                        error_log("Marketplace: Thumbnail file verified to exist");
                    } else {
                        error_log("Marketplace: WARNING: Thumbnail file not found after creation");
                    }
                } else {
                    error_log("Marketplace: Thumbnail failed: " . ($thumbResult['error'] ?? 'Unknown error'));
                }

                $imageId = $this->imageModel->create($listingId, $result['filename'], $existingCount + $uploaded);
                error_log("Marketplace: Image record created with ID: {$imageId}");
                $uploaded++;
            } else {
                error_log("Marketplace: File upload failed: " . ($result['error'] ?? 'Unknown error'));
            }
        }
        
        error_log("Marketplace: Upload complete. Uploaded {$uploaded} images.");
    }

    private function getFiltersFromRequest(): array
    {
        $filters = [];
        if (!empty($_GET['listing_type'])) $filters['listing_type'] = $_GET['listing_type'];
        if (!empty($_GET['item_type'])) $filters['item_type'] = $_GET['item_type'];
        if (!empty($_GET['country'])) $filters['country'] = trim($_GET['country']);
        if (!empty($_GET['year'])) $filters['year'] = trim($_GET['year']);
        if (!empty($_GET['year_from'])) $filters['year_from'] = $_GET['year_from'];
        if (!empty($_GET['year_to'])) $filters['year_to'] = $_GET['year_to'];
        if (!empty($_GET['condition_id'])) $filters['condition_id'] = (int)$_GET['condition_id'];
        if (!empty($_GET['material'])) $filters['material'] = $_GET['material'];
        if (!empty($_GET['price_from'])) $filters['price_from'] = (float)$_GET['price_from'];
        if (!empty($_GET['price_to'])) $filters['price_to'] = (float)$_GET['price_to'];
        if (!empty($_GET['currency'])) $filters['currency'] = $_GET['currency'];
        if (!empty($_GET['sort'])) $filters['sort'] = $_GET['sort'];
        if (!empty($_GET['q'])) $filters['q'] = trim($_GET['q']);
        return $filters;
    }
}
