<?php

require_once APP_ROOT . '/models/Coin.php';
require_once APP_ROOT . '/models/CoinImage.php';
require_once APP_ROOT . '/models/CoinVariant.php';
require_once APP_ROOT . '/models/Subcollection.php';
require_once APP_ROOT . '/models/ConditionOption.php';
require_once APP_ROOT . '/models/VariantTypeOption.php';
require_once APP_ROOT . '/models/Collection.php';

class CoinController
{
    private Coin $coinModel;
    private PDO $db;

    public function __construct()
    {
        if (!Session::isLoggedIn()) {
            header('Location: ' . APP_URL . '/login');
            exit;
        }
        $this->coinModel = new Coin();
    }

    private function nullableString(?string $value): ?string
    {
        $value = trim((string)$value);
        return $value === '' ? null : $value;
    }

    private function nullableFloat(?string $value): ?float
    {
        $value = trim((string)$value);
        return $value === '' ? null : (float)$value;
    }

    private function nullableInt(?string $value): ?int
    {
        $value = trim((string)$value);
        return $value === '' ? null : (int)$value;
    }

    public function create(string $subcollection_id): void
    {
        $subModel = new Subcollection();
        $subcollection = $subModel->getWithCollection((int)$subcollection_id);
        if (!$subcollection) {
            header('Location: ' . APP_URL . '/home');
            exit;
        }
        
        // Verify this is a coin collection
        $collectionModel = new Collection();
        $collection = $collectionModel->findById($subcollection['collection_id']);
        if (!$collection || $collection['type'] !== 'coin') {
            header('Location: ' . APP_URL . '/home');
            exit;
        }
        
        $conditionOptions = (new ConditionOption())->getByType('coin');
        require APP_ROOT . '/views/coins/create.php';
    }

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

        $subcollectionId = (int)($_POST['subcollection_id'] ?? 0);

        $data = [
            'subcollection_id'   => $subcollectionId,
            'country'            => $this->nullableString($_POST['country'] ?? null),
            'year_minted'        => $this->nullableString($_POST['year_minted'] ?? null),
            'nominal_value'      => $this->nullableString($_POST['nominal_value'] ?? null),
            'catalog_number'     => $this->nullableString($_POST['catalog_number'] ?? null),
            'material'           => $this->nullableString($_POST['material'] ?? null),
            'alloy_details'      => $this->nullableString($_POST['alloy_details'] ?? null),
            'weight'             => $this->nullableFloat($_POST['weight'] ?? null),
            'diameter'           => $this->nullableFloat($_POST['diameter'] ?? null),
            'thickness'          => $this->nullableFloat($_POST['thickness'] ?? null),
            'orientation'        => $this->nullableString($_POST['orientation'] ?? null),
            'description_obverse'=> $this->nullableString($_POST['description_obverse'] ?? null),
            'description_reverse'=> $this->nullableString($_POST['description_reverse'] ?? null),
            'legends'            => $this->nullableString($_POST['legends'] ?? null),
            'mintage'            => $this->nullableInt($_POST['mintage'] ?? null),
            'condition_id'       => $this->nullableInt($_POST['condition_id'] ?? null),
            'owned'              => isset($_POST['owned']) ? 1 : 0,
            'origin'             => $this->nullableString($_POST['origin'] ?? null),
            'purchase_price'     => $this->nullableString($_POST['purchase_price'] ?? null),
            'current_value'      => $this->nullableString($_POST['current_value'] ?? null),
            'additional_info'    => $this->nullableString($_POST['additional_info'] ?? null),
            'note'               => $this->nullableString($_POST['note'] ?? null),
        ];

        // Handle obverse image upload
        if (!empty($_FILES['image_obverse']['name'])) {
            $result = FileUpload::upload($_FILES['image_obverse'], UPLOAD_ITEMS_PATH, ALLOWED_IMAGE_TYPES);
            if ($result['success']) {
                $data['image_obverse'] = $result['filename'];
                // Create thumbnail for coin (160x160)
                $thumbPath = FileUpload::getThumbnailPath($result['filepath'], UPLOAD_ITEMS_THUMBS_PATH);
                FileUpload::createThumbnail($result['filepath'], $thumbPath, 160, 160, 70);
            } else {
                Session::flash('error', $result['error']);
                header('Location: ' . APP_URL . '/subcollections/' . $subcollectionId . '/coins/create');
                exit;
            }
        } elseif (!empty($_POST['numista_image_obverse'])) {
            // Handle Numista downloaded image
            $data['image_obverse'] = $_POST['numista_image_obverse'];
            // Create thumbnail for coin (160x160)
            $thumbPath = FileUpload::getThumbnailPath(UPLOAD_ITEMS_PATH . '/' . $_POST['numista_image_obverse'], UPLOAD_ITEMS_THUMBS_PATH);
            FileUpload::createThumbnail(UPLOAD_ITEMS_PATH . '/' . $_POST['numista_image_obverse'], $thumbPath, 160, 160, 70);
        }

        // Handle reverse image upload
        if (!empty($_FILES['image_reverse']['name'])) {
            $result = FileUpload::upload($_FILES['image_reverse'], UPLOAD_ITEMS_PATH, ALLOWED_IMAGE_TYPES);
            if ($result['success']) {
                $data['image_reverse'] = $result['filename'];
                // Create thumbnail for coin (160x160)
                $thumbPath = FileUpload::getThumbnailPath($result['filepath'], UPLOAD_ITEMS_THUMBS_PATH);
                FileUpload::createThumbnail($result['filepath'], $thumbPath, 160, 160, 70);
            } else {
                Session::flash('error', $result['error']);
                header('Location: ' . APP_URL . '/subcollections/' . $subcollectionId . '/coins/create');
                exit;
            }
        } elseif (!empty($_POST['numista_image_reverse'])) {
            // Handle Numista downloaded image
            $data['image_reverse'] = $_POST['numista_image_reverse'];
            // Create thumbnail for coin (160x160)
            $thumbPath = FileUpload::getThumbnailPath(UPLOAD_ITEMS_PATH . '/' . $_POST['numista_image_reverse'], UPLOAD_ITEMS_THUMBS_PATH);
            FileUpload::createThumbnail(UPLOAD_ITEMS_PATH . '/' . $_POST['numista_image_reverse'], $thumbPath, 160, 160, 70);
        }

        $coinId = $this->coinModel->create($data);

        // Handle additional images upload
        if (!empty($_FILES['additional_images']['name'][0])) {
            $imageModel = new CoinImage();
            foreach ($_FILES['additional_images']['name'] as $i => $name) {
                if (empty($name)) continue;
                $file = [
                    'name'     => $_FILES['additional_images']['name'][$i],
                    'type'     => $_FILES['additional_images']['type'][$i],
                    'tmp_name' => $_FILES['additional_images']['tmp_name'][$i],
                    'error'    => $_FILES['additional_images']['error'][$i],
                    'size'     => $_FILES['additional_images']['size'][$i],
                ];
                $result = FileUpload::upload($file, UPLOAD_ITEMS_PATH, ALLOWED_IMAGE_TYPES);
                if ($result['success']) {
                    // Create thumbnail for coin (160x160)
                    $thumbPath = FileUpload::getThumbnailPath($result['filepath'], UPLOAD_ITEMS_THUMBS_PATH);
                    FileUpload::createThumbnail($result['filepath'], $thumbPath, 160, 160, 70);
                    
                    $imageModel->create([
                        'coin_id'    => $coinId,
                        'filename'   => $result['filename'],
                        'sort_order' => $i,
                    ]);
                }
            }
        }

        // Handle variants
        if (!empty($_POST['variant_condition'])) {
            $variantModel = new CoinVariant();
            foreach ($_POST['variant_condition'] as $i => $conditionId) {
                $variantData = [
                    'coin_id'         => $coinId,
                    'condition_id'    => !empty($conditionId) ? (int)$conditionId : null,
                    'note'            => trim($_POST['variant_note'][$i] ?? '') ?: null,
                    'owned'           => isset($_POST['variant_owned'][$i]) ? 1 : 0,
                    'sort_order'      => $i,
                ];
                $variantModel->create($variantData);
            }
        }

        $view = $_POST['view'] ?? 'grid';
        Session::flash('success', Lang::get('coin_created'));
        header('Location: ' . APP_URL . '/subcollections/' . $subcollectionId . '?view=' . urlencode($view));
        exit;
    }

    public function edit(string $id): void
    {
        $coin = $this->coinModel->findWithContext((int)$id);
        if (!$coin) {
            header('Location: ' . APP_URL . '/home');
            exit;
        }

        // Verify this is a coin collection
        $collectionModel = new Collection();
        $collection = $collectionModel->findById($coin['collection_id']);
        if (!$collection || $collection['type'] !== 'coin') {
            header('Location: ' . APP_URL . '/home');
            exit;
        }

        $conditionOptions = (new ConditionOption())->getByType('coin');
        $additionalImages = (new CoinImage())->getAllByCoin((int)$id);
        $variants = (new CoinVariant())->getAllByCoin((int)$id);
        
        require APP_ROOT . '/views/coins/edit.php';
    }

    public function update(string $id): void
    {
        if (!Session::verifyCsrfToken($_POST['csrf_token'] ?? '')) {
            Session::flash('error', 'Invalid request.');
            header('Location: ' . APP_URL . '/coins/' . $id . '/edit');
            exit;
        }

        
        $coin = $this->coinModel->findById((int)$id);
        if (!$coin) {
            header('Location: ' . APP_URL . '/home');
            exit;
        }

        $data = [
            'country'            => $this->nullableString($_POST['country'] ?? null),
            'year_minted'        => $this->nullableString($_POST['year_minted'] ?? null),
            'nominal_value'      => $this->nullableString($_POST['nominal_value'] ?? null),
            'catalog_number'     => $this->nullableString($_POST['catalog_number'] ?? null),
            'material'           => $this->nullableString($_POST['material'] ?? null),
            'alloy_details'      => $this->nullableString($_POST['alloy_details'] ?? null),
            'weight'             => $this->nullableFloat($_POST['weight'] ?? null),
            'diameter'           => $this->nullableFloat($_POST['diameter'] ?? null),
            'thickness'          => $this->nullableFloat($_POST['thickness'] ?? null),
            'orientation'        => $this->nullableString($_POST['orientation'] ?? null),
            'description_obverse'=> $this->nullableString($_POST['description_obverse'] ?? null),
            'description_reverse'=> $this->nullableString($_POST['description_reverse'] ?? null),
            'legends'            => $this->nullableString($_POST['legends'] ?? null),
            'mintage'            => $this->nullableInt($_POST['mintage'] ?? null),
            'condition_id'       => $this->nullableInt($_POST['condition_id'] ?? null),
            'owned'              => isset($_POST['owned']) ? 1 : 0,
            'origin'             => $this->nullableString($_POST['origin'] ?? null),
            'purchase_price'     => $this->nullableString($_POST['purchase_price'] ?? null),
            'current_value'      => $this->nullableString($_POST['current_value'] ?? null),
            'additional_info'    => $this->nullableString($_POST['additional_info'] ?? null),
            'note'               => $this->nullableString($_POST['note'] ?? null),
        ];

        // Zadrži postojeće slike ako se ne upload-uju nove
        if (!empty($_FILES['image_obverse']['name'])) {
            $result = FileUpload::upload($_FILES['image_obverse'], UPLOAD_ITEMS_PATH, ALLOWED_IMAGE_TYPES);
            if ($result['success']) {
                // Delete old obverse image only if it's not a duplicate
                if ($coin['image_obverse'] && !str_starts_with($coin['image_obverse'], 'duplicate_')) {
                    FileUpload::delete(UPLOAD_ITEMS_PATH . '/' . $coin['image_obverse']);
                    // Delete old thumbnail
                    $oldThumbPath = FileUpload::getThumbnailPath(UPLOAD_ITEMS_PATH . '/' . $coin['image_obverse'], UPLOAD_ITEMS_THUMBS_PATH);
                    FileUpload::delete($oldThumbPath);
                }
                $data['image_obverse'] = $result['filename'];
                // Create thumbnail for coin (160x160)
                $thumbPath = FileUpload::getThumbnailPath($result['filepath'], UPLOAD_ITEMS_THUMBS_PATH);
                FileUpload::createThumbnail($result['filepath'], $thumbPath, 160, 160, 70);
            } else {
                Session::flash('error', $result['error']);
                header('Location: ' . APP_URL . '/coins/' . $id . '/edit');
                exit;
            }
        } elseif (!empty($_POST['numista_image_obverse'])) {
            // Handle Numista downloaded image
            if ($coin['image_obverse'] && !str_starts_with($coin['image_obverse'], 'duplicate_')) {
                FileUpload::delete(UPLOAD_ITEMS_PATH . '/' . $coin['image_obverse']);
                // Delete old thumbnail
                $oldThumbPath = FileUpload::getThumbnailPath(UPLOAD_ITEMS_PATH . '/' . $coin['image_obverse'], UPLOAD_ITEMS_THUMBS_PATH);
                FileUpload::delete($oldThumbPath);
            }
            $data['image_obverse'] = $_POST['numista_image_obverse'];
            // Create thumbnail for coin (160x160)
            $thumbPath = FileUpload::getThumbnailPath(UPLOAD_ITEMS_PATH . '/' . $_POST['numista_image_obverse'], UPLOAD_ITEMS_THUMBS_PATH);
            FileUpload::createThumbnail(UPLOAD_ITEMS_PATH . '/' . $_POST['numista_image_obverse'], $thumbPath, 160, 160, 70);
        } else {
            $data['image_obverse'] = $coin['image_obverse'];
        }

        if (!empty($_FILES['image_reverse']['name'])) {
            $result = FileUpload::upload($_FILES['image_reverse'], UPLOAD_ITEMS_PATH, ALLOWED_IMAGE_TYPES);
            if ($result['success']) {
                // Delete old reverse image only if it's not a duplicate
                if ($coin['image_reverse'] && !str_starts_with($coin['image_reverse'], 'duplicate_')) {
                    FileUpload::delete(UPLOAD_ITEMS_PATH . '/' . $coin['image_reverse']);
                    // Delete old thumbnail
                    $oldThumbPath = FileUpload::getThumbnailPath(UPLOAD_ITEMS_PATH . '/' . $coin['image_reverse'], UPLOAD_ITEMS_THUMBS_PATH);
                    FileUpload::delete($oldThumbPath);
                }
                $data['image_reverse'] = $result['filename'];
                // Create thumbnail for coin (160x160)
                $thumbPath = FileUpload::getThumbnailPath($result['filepath'], UPLOAD_ITEMS_THUMBS_PATH);
                FileUpload::createThumbnail($result['filepath'], $thumbPath, 160, 160, 70);
            } else {
                Session::flash('error', $result['error']);
                header('Location: ' . APP_URL . '/coins/' . $id . '/edit');
                exit;
            }
        } elseif (!empty($_POST['numista_image_reverse'])) {
            // Handle Numista downloaded image
            if ($coin['image_reverse'] && !str_starts_with($coin['image_reverse'], 'duplicate_')) {
                FileUpload::delete(UPLOAD_ITEMS_PATH . '/' . $coin['image_reverse']);
                // Delete old thumbnail
                $oldThumbPath = FileUpload::getThumbnailPath(UPLOAD_ITEMS_PATH . '/' . $coin['image_reverse'], UPLOAD_ITEMS_THUMBS_PATH);
                FileUpload::delete($oldThumbPath);
            }
            $data['image_reverse'] = $_POST['numista_image_reverse'];
            // Create thumbnail for coin (160x160)
            $thumbPath = FileUpload::getThumbnailPath(UPLOAD_ITEMS_PATH . '/' . $_POST['numista_image_reverse'], UPLOAD_ITEMS_THUMBS_PATH);
            FileUpload::createThumbnail(UPLOAD_ITEMS_PATH . '/' . $_POST['numista_image_reverse'], $thumbPath, 160, 160, 70);
        } else {
            $data['image_reverse'] = $coin['image_reverse'];
        }

        $this->coinModel->update((int)$id, $data);

        // Handle additional images upload
        if (!empty($_FILES['additional_images']['name'][0])) {
            $imageModel = new CoinImage();
            foreach ($_FILES['additional_images']['name'] as $i => $name) {
                if (empty($name)) continue;
                $file = [
                    'name'     => $_FILES['additional_images']['name'][$i],
                    'type'     => $_FILES['additional_images']['type'][$i],
                    'tmp_name' => $_FILES['additional_images']['tmp_name'][$i],
                    'error'    => $_FILES['additional_images']['error'][$i],
                    'size'     => $_FILES['additional_images']['size'][$i],
                ];
                $result = FileUpload::upload($file, UPLOAD_ITEMS_PATH, ALLOWED_IMAGE_TYPES);
                if ($result['success']) {
                    // Create thumbnail for coin (160x160)
                    $thumbPath = FileUpload::getThumbnailPath($result['filepath'], UPLOAD_ITEMS_THUMBS_PATH);
                    FileUpload::createThumbnail($result['filepath'], $thumbPath, 160, 160, 70);
                    
                    $imageModel->create([
                        'coin_id'    => (int)$id,
                        'filename'   => $result['filename'],
                        'sort_order' => $i,
                    ]);
                }
            }
        }

        // Handle image deletions
        if (!empty($_POST['delete_images'])) {
            $imageModel = new CoinImage();
            foreach ($_POST['delete_images'] as $imageId) {
                $imageModel->delete((int)$imageId);
            }
        }

        // Handle variants - delete existing and create new ones
        $variantModel = new CoinVariant();
        $variantModel->deleteByCoin((int)$id);
        
        if (!empty($_POST['variant_condition'])) {
            foreach ($_POST['variant_condition'] as $i => $conditionId) {
                $variantData = [
                    'coin_id'         => (int)$id,
                    'condition_id'    => !empty($conditionId) ? (int)$conditionId : null,
                    'note'            => trim($_POST['variant_note'][$i] ?? '') ?: null,
                    'owned'           => isset($_POST['variant_owned'][$i]) ? 1 : 0,
                    'sort_order'      => $i,
                ];
                $variantModel->create($variantData);
            }
        }

        $view = $_POST['view'] ?? 'grid';
        Session::flash('success', Lang::get('coin_updated'));
        header('Location: ' . APP_URL . '/subcollections/' . $coin['subcollection_id'] . '?view=' . urlencode($view));
        exit;
    }

    public function duplicate(string $id): void
    {
        header('Content-Type: application/json');
        
        if (!Session::verifyCsrfToken($_POST['csrf_token'] ?? '')) {
            http_response_code(403);
            echo json_encode(['error' => 'Invalid token']);
            exit;
        }

        $coin = $this->coinModel->findWithContext((int)$id);
        if (!$coin) {
            http_response_code(404);
            echo json_encode(['error' => 'Coin not found']);
            exit;
        }

        // Check if user owns this coin through collection
        $collectionModel = new Collection();
        $collection = $collectionModel->findById($coin['collection_id']);
        if (!$collection || $collection['user_id'] !== Session::getUserId()) {
            http_response_code(403);
            echo json_encode(['error' => 'Access denied']);
            exit;
        }

        try {
            $this->db = Database::getInstance();
            $this->db->beginTransaction();

            // Copy image files if they exist
            $newObverseImage = null;
            $newReverseImage = null;
            
            if ($coin['image_obverse']) {
                $oldPath = APP_ROOT . '/public/uploads/coins/' . $coin['image_obverse'];
                if (file_exists($oldPath)) {
                    $newObverseImage = 'duplicate_' . time() . '_' . $coin['image_obverse'];
                    $newPath = APP_ROOT . '/public/uploads/coins/' . $newObverseImage;
                    copy($oldPath, $newPath);
                }
            }
            
            if ($coin['image_reverse']) {
                $oldPath = APP_ROOT . '/public/uploads/coins/' . $coin['image_reverse'];
                if (file_exists($oldPath)) {
                    $newReverseImage = 'duplicate_' . time() . '_' . $coin['image_reverse'];
                    $newPath = APP_ROOT . '/public/uploads/coins/' . $newReverseImage;
                    copy($oldPath, $newPath);
                }
            }

            // Create new coin with same data
            $newCoinId = $this->coinModel->create([
                'subcollection_id' => $coin['subcollection_id'],
                'image_obverse'    => $newObverseImage,
                'image_reverse'    => $newReverseImage,
                'country'          => $coin['country'],
                'year_minted'      => $coin['year_minted'],
                'nominal_value'    => $coin['nominal_value'],
                'catalog_number'   => $coin['catalog_number'],
                'material'         => $coin['material'],
                'alloy_details'    => $coin['alloy_details'],
                'weight'           => $coin['weight'],
                'diameter'         => $coin['diameter'],
                'thickness'        => $coin['thickness'],
                'orientation'      => $coin['orientation'],
                'description_obverse' => $coin['description_obverse'],
                'description_reverse' => $coin['description_reverse'],
                'legends'          => $coin['legends'],
                'mintage'          => $coin['mintage'],
                'condition_id'     => $coin['condition_id'],
                'owned'            => $coin['owned'],
                'origin'           => $coin['origin'],
                'purchase_price'   => $coin['purchase_price'],
                'current_value'    => $coin['current_value'],
                'additional_info'  => $coin['additional_info'],
                'note'             => $coin['note'] . ' (kopija)',
                'sort_order'       => $this->coinModel->getNextSortOrder($coin['subcollection_id']),
            ]);

            // Copy additional images
            $imageModel = new CoinImage();
            $images = $imageModel->getAllByCoin($coin['id']);
            foreach ($images as $image) {
                // Copy the image file
                $newFilename = null;
                if ($image['filename']) {
                    $oldPath = APP_ROOT . '/public/uploads/coins/' . $image['filename'];
                    if (file_exists($oldPath)) {
                        $newFilename = 'duplicate_' . time() . '_' . $image['filename'];
                        $newPath = APP_ROOT . '/public/uploads/coins/' . $newFilename;
                        copy($oldPath, $newPath);
                    }
                }
                
                $imageModel->create([
                    'coin_id'     => $newCoinId,
                    'filename'    => $newFilename,
                    'sort_order'  => $image['sort_order'],
                ]);
            }

            $this->db->commit();
            echo json_encode(['success' => true, 'coin_id' => $newCoinId]);
        } catch (Exception $e) {
            $this->db->rollBack();
            http_response_code(500);
            echo json_encode(['error' => 'Failed to duplicate coin']);
        }
    }

    public function delete(string $id): void
    {
        $coin = $this->coinModel->findById((int)$id);
        if (!$coin) {
            header('Location: ' . APP_URL . '/home');
            exit;
        }

        $subcollectionId = $coin['subcollection_id'];
        
        // Delete additional images
        (new CoinImage())->deleteByCoinId((int)$id);
        
        // Delete coin
        $this->coinModel->delete((int)$id);
        
        Session::flash('success', Lang::get('coin_deleted'));
        header('Location: ' . APP_URL . '/subcollections/' . $subcollectionId);
        exit;
    }

    public function moveUp(string $id): void
    {
        $coin = $this->coinModel->findById((int)$id);
        if ($coin && $this->coinModel->moveUp((int)$id)) {
            Session::flash('success', Lang::get('item_moved_up'));
        } else {
            Session::flash('error', Lang::get('cannot_move_item'));
        }
        header('Location: ' . APP_URL . '/subcollections/' . $coin['subcollection_id']);
        exit;
    }

    public function moveDown(string $id): void
    {
        $coin = $this->coinModel->findById((int)$id);
        if ($coin && $this->coinModel->moveDown((int)$id)) {
            Session::flash('success', Lang::get('item_moved_down'));
        } else {
            Session::flash('error', Lang::get('cannot_move_item'));
        }
        header('Location: ' . APP_URL . '/subcollections/' . $coin['subcollection_id']);
        exit;
    }

    public function toggleOwned(string $id): void
    {
        header('Content-Type: application/json');
        
        if (!Session::verifyCsrfToken($_POST['csrf_token'] ?? '')) {
            echo json_encode(['success' => false]);
            exit;
        }

        $coin = $this->coinModel->findById((int)$id);
        if ($coin && $this->coinModel->toggleOwned((int)$id)) {
            echo json_encode(['success' => true]);
        } else {
            echo json_encode(['success' => false]);
        }
        exit;
    }

    public function toggleVariantOwned(string $id): void
    {
        header('Content-Type: application/json');
        
        if (!Session::verifyCsrfToken($_POST['csrf_token'] ?? '')) {
            echo json_encode(['success' => false]);
            exit;
        }

        $variantModel = new CoinVariant();
        $variant = $variantModel->findById((int)$id);
        if (!$variant) {
            echo json_encode(['success' => false]);
            exit;
        }

        // Check if user owns this coin through collection
        $coin = $this->coinModel->findWithContext($variant['coin_id']);
        if (!$coin) {
            echo json_encode(['success' => false]);
            exit;
        }

        $variantModel->toggleOwned((int)$id);
        echo json_encode(['success' => true]);
    }
}
