<?php

require_once APP_ROOT . '/models/User.php';
require_once APP_ROOT . '/models/Collection.php';
require_once APP_ROOT . '/models/Subcollection.php';
require_once APP_ROOT . '/models/Item.php';
require_once APP_ROOT . '/models/ItemVariant.php';
require_once APP_ROOT . '/models/ItemImage.php';
require_once APP_ROOT . '/models/Coin.php';
require_once APP_ROOT . '/models/CoinImage.php';

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

    public function edit(): void
    {
        $userModel = new User();
        $user = $userModel->findById(Session::getUserId());
        
        $collectionModel = new Collection();
        $collections = $collectionModel->getAllByUser(Session::getUserId());
        
        require APP_ROOT . '/views/profile/edit.php';
    }

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

        $displayName = trim($_POST['display_name'] ?? '');
        $email = trim($_POST['email'] ?? '');

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

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

        $userModel = new User();
        $user = $userModel->findById(Session::getUserId());
        $userModel->update(Session::getUserId(), [
            'display_name'     => $displayName,
            'email'            => $email,
            'default_view'     => $user['default_view'] ?? 'grid',
            'default_language' => $user['default_language'] ?? 'en',
        ]);

        Session::set('display_name', $displayName);
        Session::flash('success', Lang::get('profile_updated'));
        header('Location: ' . APP_URL . '/profile');
        exit;
    }

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

        $defaultView = in_array($_POST['default_view'] ?? '', ['grid', 'table']) ? $_POST['default_view'] : 'grid';
        $defaultLanguage = in_array($_POST['default_language'] ?? '', ['en', 'cn', 'cs', 'de', 'el', 'es', 'fr', 'hu', 'il','it','jp', 'nl', 'no', 'pl', 'pt', 'ro', 'ru', 'sr', 'sv', 'tr']) ? $_POST['default_language'] : 'en';
        $defaultTheme = in_array($_POST['default_theme'] ?? '', ['light', 'dark', 'system']) ? $_POST['default_theme'] : 'system';

        $userModel = new User();
        $user = $userModel->findById(Session::getUserId());
        $userModel->update(Session::getUserId(), [
            'display_name'     => $user['display_name'],
            'email'            => $user['email'],
            'default_view'     => $defaultView,
            'default_language' => $defaultLanguage,
            'default_theme'    => $defaultTheme,
        ]);

        Session::set('default_view', $defaultView);
        Session::set('default_language', $defaultLanguage);
        Session::set('default_theme', $defaultTheme);
        Lang::setLocale($defaultLanguage);

        Session::flash('success', Lang::get('preferences_saved'));
        header('Location: ' . APP_URL . '/profile');
        exit;
    }

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

        if (empty($_FILES['avatar']['name'])) {
            Session::flash('error', Lang::get('no_file_selected'));
            header('Location: ' . APP_URL . '/profile');
            exit;
        }

        $result = FileUpload::upload($_FILES['avatar'], UPLOAD_AVATARS_PATH, ALLOWED_IMAGE_TYPES);

        if (!$result['success']) {
            Session::flash('error', $result['error']);
            header('Location: ' . APP_URL . '/profile');
            exit;
        }

        $userModel = new User();
        $user = $userModel->findById(Session::getUserId());

        // Delete old avatar
        if (!empty($user['avatar'])) {
            FileUpload::delete(UPLOAD_AVATARS_PATH . '/' . $user['avatar']);
        }

        $userModel->updateAvatar(Session::getUserId(), $result['filename']);
        Session::set('avatar', $result['filename']);

        Session::flash('success', Lang::get('avatar_updated'));
        header('Location: ' . APP_URL . '/profile');
        exit;
    }

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

        $currentPassword = $_POST['current_password'] ?? '';
        $newPassword = $_POST['new_password'] ?? '';
        $confirmPassword = $_POST['confirm_password'] ?? '';

        $userModel = new User();
        $user = $userModel->findById(Session::getUserId());

        if (!password_verify($currentPassword, $user['password'])) {
            Session::flash('error', Lang::get('password_wrong'));
            header('Location: ' . APP_URL . '/profile');
            exit;
        }

        if ($newPassword !== $confirmPassword) {
            Session::flash('error', Lang::get('password_mismatch'));
            header('Location: ' . APP_URL . '/profile');
            exit;
        }

        $validator = new Validator();
        $validator->minLength('new_password', $newPassword, 6, Lang::get('new_password'));

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

        $hashed = password_hash($newPassword, PASSWORD_BCRYPT);
        $userModel->updatePassword(Session::getUserId(), $hashed);

        Session::flash('success', Lang::get('password_updated'));
        header('Location: ' . APP_URL . '/profile');
        exit;
    }

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

        $collectionId = (int)($_POST['collection_id'] ?? 0);
        $allowSharing = (int)($_POST['allow_sharing'] ?? 0);

        $collectionModel = new Collection();
        $collection = $collectionModel->findById($collectionId);

        if (!$collection || $collection['user_id'] !== Session::getUserId()) {
            Session::flash('error', 'Collection not found or access denied.');
            header('Location: ' . APP_URL . '/profile');
            exit;
        }

        $collectionModel->setAllowSharing($collectionId, $allowSharing);
        Session::flash('success', 'Sharing permission updated successfully.');
        header('Location: ' . APP_URL . '/profile');
        exit;
    }

    public function export(): void
    {
        $userId = Session::getUserId();
        
        // Create backup data structure
        $backup = [
            'version' => 1,
            'exported_at' => date('Y-m-d\TH:i:s'),
            'collections' => []
        ];

        $collectionModel = new Collection();
        $subcollectionModel = new Subcollection();
        $itemModel = new Item();
        $variantModel = new ItemVariant();
        $itemImageModel = new ItemImage();
        $coinModel = new Coin();
        $coinImageModel = new CoinImage();

        $collections = $collectionModel->getAllByUser($userId);
        
        foreach ($collections as $collection) {
            $collectionData = [
                'name' => $collection['name'],
                'description' => $collection['description'],
                'sort_order' => $collection['sort_order'],
                'type' => $collection['type'] ?? 'banknote',
                'subcollections' => []
            ];

            $subcollections = $subcollectionModel->getAllByCollection($collection['id']);
            
            foreach ($subcollections as $subcollection) {
                $subcollectionData = [
                    'name' => $subcollection['name'],
                    'description' => $subcollection['description'],
                    'sort_order' => $subcollection['sort_order']
                ];

                if ($collection['type'] === 'coin') {
                    // Handle coins
                    $subcollectionData['coins'] = [];
                    $coins = $coinModel->getAllBySubcollection($subcollection['id']);
                    
                    foreach ($coins as $coin) {
                        $coinData = [
                            'image_obverse' => $coin['image_obverse'],
                            'image_reverse' => $coin['image_reverse'],
                            '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'],
                            'sort_order' => $coin['sort_order'],
                            'additional_images' => []
                        ];

                        // Get additional coin images
                        $additionalImages = $coinImageModel->getAllByCoin($coin['id']);
                        foreach ($additionalImages as $img) {
                            $coinData['additional_images'][] = [
                                'filename' => $img['filename'],
                                'sort_order' => $img['sort_order']
                            ];
                        }

                        $subcollectionData['coins'][] = $coinData;
                    }
                } else {
                    // Handle banknotes (items)
                    $subcollectionData['items'] = [];
                    $items = $itemModel->getAllBySubcollection($subcollection['id']);
                    
                    foreach ($items as $item) {
                        $itemData = [
                            'image_obverse' => $item['image_obverse'],
                            'image_reverse' => $item['image_reverse'],
                            'nominal_value' => $item['nominal_value'],
                            'dimensions' => $item['dimensions'],
                            'color' => $item['color'],
                            'description_obverse' => $item['description_obverse'],
                            'description_reverse' => $item['description_reverse'],
                            'issue_date' => $item['issue_date'],
                            'additional_info' => $item['additional_info'],
                            'catalog_number' => $item['catalog_number'],
                            'country' => $item['country'],
                            'purchase_price' => $item['purchase_price'],
                            'note' => $item['note'],
                            'sort_order' => $item['sort_order'],
                            'variants' => [],
                            'additional_images' => []
                        ];

                        // Get variants
                        $variants = $variantModel->getAllByItem($item['id']);
                        foreach ($variants as $variant) {
                            $itemData['variants'][] = [
                                'condition_id' => $variant['condition_id'],
                                'variant_type_id' => $variant['variant_type_id'],
                                'note' => $variant['note'],
                                'owned' => $variant['owned'],
                                'sort_order' => $variant['sort_order']
                            ];
                        }

                        // Get additional item images
                        $additionalImages = $itemImageModel->getAllByItem($item['id']);
                        foreach ($additionalImages as $img) {
                            $itemData['additional_images'][] = [
                                'filename' => $img['filename'],
                                'sort_order' => $img['sort_order']
                            ];
                        }

                        $subcollectionData['items'][] = $itemData;
                    }
                }

                $collectionData['subcollections'][] = $subcollectionData;
            }

            $backup['collections'][] = $collectionData;
        }

        // Create ZIP file
        $zipFile = tempnam(sys_get_temp_dir(), 'backup_');
        $zip = new ZipArchive();
        
        if ($zip->open($zipFile, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== TRUE) {
            unlink($zipFile);
            Session::flash('error', 'Could not create backup file');
            header('Location: ' . APP_URL . '/profile');
            exit;
        }

        // Add JSON backup to ZIP
        $zip->addFromString('backup.json', json_encode($backup, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));

        // Add images to ZIP
        $imageFiles = [];
        $this->collectImageFiles($backup, $imageFiles);
        
        foreach ($imageFiles as $filename) {
            if (!empty($filename)) {
                $sourcePath = UPLOAD_ITEMS_PATH . '/' . $filename;
                if (file_exists($sourcePath)) {
                    $zip->addFile($sourcePath, 'images/' . $filename);
                }
            }
        }

        $zip->close();

        // Send ZIP file to browser
        header('Content-Type: application/zip');
        header('Content-Disposition: attachment; filename="notaphilycatalogue_backup_' . date('Y-m-d_H-i-s') . '.zip"');
        header('Content-Length: ' . filesize($zipFile));
        header('Cache-Control: no-cache, must-revalidate');
        header('Pragma: no-cache');

        readfile($zipFile);
        unlink($zipFile);
        exit;
    }

    private function collectImageFiles(array $data, array &$files): void
    {
        foreach ($data as $key => $value) {
            if (is_array($value)) {
                $this->collectImageFiles($value, $files);
            } elseif (in_array($key, ['image_obverse', 'image_reverse', 'filename']) && !empty($value)) {
                if (!in_array($value, $files)) {
                    $files[] = $value;
                }
            }
        }
    }

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

        if (empty($_FILES['backup_file']['name'])) {
            Session::flash('error', Lang::get('no_file_selected'));
            header('Location: ' . APP_URL . '/profile');
            exit;
        }

        $uploadedFile = $_FILES['backup_file'];
        if ($uploadedFile['type'] !== 'application/zip' && $uploadedFile['type'] !== 'application/x-zip-compressed') {
            Session::flash('error', 'Invalid file type. Please upload a ZIP file.');
            header('Location: ' . APP_URL . '/profile');
            exit;
        }

        $mode = $_POST['import_mode'] ?? 'add';
        $userId = Session::getUserId();

        // Extract ZIP file
        $tempDir = tempnam(sys_get_temp_dir(), 'import_');
        unlink($tempDir);
        mkdir($tempDir, 0755);

        $zip = new ZipArchive();
        if ($zip->open($uploadedFile['tmp_name']) !== TRUE) {
            Session::flash('error', 'Could not open backup file');
            $this->cleanupTempDir($tempDir);
            header('Location: ' . APP_URL . '/profile');
            exit;
        }

        $zip->extractTo($tempDir);
        $zip->close();

        // Validate backup.json
        $backupFile = $tempDir . '/backup.json';
        if (!file_exists($backupFile)) {
            Session::flash('error', 'Invalid backup file: backup.json not found');
            $this->cleanupTempDir($tempDir);
            header('Location: ' . APP_URL . '/profile');
            exit;
        }

        $backupData = json_decode(file_get_contents($backupFile), true);
        if (!$backupData || !isset($backupData['collections'])) {
            Session::flash('error', 'Invalid backup file format');
            $this->cleanupTempDir($tempDir);
            header('Location: ' . APP_URL . '/profile');
            exit;
        }

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

            // If replace mode, delete existing collections
            if ($mode === 'replace') {
                $this->deleteUserCollections($userId);
            }

            // Import collections
            $this->importCollections($backupData['collections'], $userId, $tempDir);

            $this->db->commit();
            Session::flash('success', Lang::get('backup_imported_successfully'));
        } catch (Exception $e) {
            $this->db->rollBack();
            Session::flash('error', 'Import failed: ' . $e->getMessage());
        }

        $this->cleanupTempDir($tempDir);
        header('Location: ' . APP_URL . '/profile');
        exit;
    }

    private function deleteUserCollections(int $userId): void
    {
        // Get all collections with their images
        $stmt = $this->db->prepare('SELECT * FROM collections WHERE user_id = :user_id');
        $stmt->execute(['user_id' => $userId]);
        $collections = $stmt->fetchAll();

        foreach ($collections as $collection) {
            $this->deleteCollectionImages($collection['id']);
        }

        // Delete collections (CASCADE will handle subcollections, items, variants, images)
        $stmt = $this->db->prepare('DELETE FROM collections WHERE user_id = :user_id');
        $stmt->execute(['user_id' => $userId]);
    }

    private function deleteCollectionImages(int $collectionId): void
    {
        // Get all items/coins in this collection and delete their images
        $stmt = $this->db->prepare(
            'SELECT i.id, i.image_obverse, i.image_reverse 
             FROM items i 
             JOIN subcollections s ON i.subcollection_id = s.id 
             WHERE s.collection_id = :collection_id'
        );
        $stmt->execute(['collection_id' => $collectionId]);
        $items = $stmt->fetchAll();

        foreach ($items as $item) {
            if ($item['image_obverse']) {
                FileUpload::delete(UPLOAD_ITEMS_PATH . '/' . $item['image_obverse']);
            }
            if ($item['image_reverse']) {
                FileUpload::delete(UPLOAD_ITEMS_PATH . '/' . $item['image_reverse']);
            }
        }

        // Get coins
        $stmt = $this->db->prepare(
            'SELECT c.id, c.image_obverse, c.image_reverse 
             FROM coins c 
             JOIN subcollections s ON c.subcollection_id = s.id 
             WHERE s.collection_id = :collection_id'
        );
        $stmt->execute(['collection_id' => $collectionId]);
        $coins = $stmt->fetchAll();

        foreach ($coins as $coin) {
            if ($coin['image_obverse']) {
                FileUpload::delete(UPLOAD_ITEMS_PATH . '/' . $coin['image_obverse']);
            }
            if ($coin['image_reverse']) {
                FileUpload::delete(UPLOAD_ITEMS_PATH . '/' . $coin['image_reverse']);
            }
        }

        // Additional images will be deleted automatically by CASCADE
    }

    private function importCollections(array $collections, int $userId, string $tempDir): void
    {
        $collectionModel = new Collection();
        $subcollectionModel = new Subcollection();
        $itemModel = new Item();
        $variantModel = new ItemVariant();
        $itemImageModel = new ItemImage();
        $coinModel = new Coin();
        $coinImageModel = new CoinImage();

        foreach ($collections as $collectionData) {
            $collectionId = $collectionModel->create([
                'user_id' => $userId,
                'name' => $collectionData['name'],
                'description' => $collectionData['description'] ?? null,
                'sort_order' => $collectionData['sort_order'] ?? 0,
                'type' => $collectionData['type'] ?? 'banknote'
            ]);

            foreach ($collectionData['subcollections'] as $subcollectionData) {
                $subcollectionId = $subcollectionModel->create([
                    'collection_id' => $collectionId,
                    'name' => $subcollectionData['name'],
                    'description' => $subcollectionData['description'] ?? null,
                    'sort_order' => $subcollectionData['sort_order'] ?? 0
                ]);

                // Handle items or coins based on collection type
                if ($collectionData['type'] === 'coin' && isset($subcollectionData['coins'])) {
                    foreach ($subcollectionData['coins'] as $coinData) {
                        $newObverse = $this->importImage($coinData['image_obverse'], $tempDir);
                        $newReverse = $this->importImage($coinData['image_reverse'], $tempDir);

                        $coinId = $coinModel->create([
                            'subcollection_id' => $subcollectionId,
                            'image_obverse' => $newObverse,
                            'image_reverse' => $newReverse,
                            'country' => $coinData['country'] ?? null,
                            'year_minted' => $coinData['year_minted'] ?? null,
                            'nominal_value' => $coinData['nominal_value'] ?? null,
                            'catalog_number' => $coinData['catalog_number'] ?? null,
                            'material' => $coinData['material'] ?? null,
                            'alloy_details' => $coinData['alloy_details'] ?? null,
                            'weight' => $coinData['weight'] ?? null,
                            'diameter' => $coinData['diameter'] ?? null,
                            'thickness' => $coinData['thickness'] ?? null,
                            'orientation' => $coinData['orientation'] ?? null,
                            'description_obverse' => $coinData['description_obverse'] ?? null,
                            'description_reverse' => $coinData['description_reverse'] ?? null,
                            'legends' => $coinData['legends'] ?? null,
                            'mintage' => $coinData['mintage'] ?? null,
                            'condition_id' => $coinData['condition_id'] ?? null,
                            'owned' => $coinData['owned'] ?? 0,
                            'origin' => $coinData['origin'] ?? null,
                            'purchase_price' => $coinData['purchase_price'] ?? null,
                            'current_value' => $coinData['current_value'] ?? null,
                            'additional_info' => $coinData['additional_info'] ?? null,
                            'note' => $coinData['note'] ?? null,
                            'sort_order' => $coinData['sort_order'] ?? 0
                        ]);

                        // Import additional coin images
                        if (isset($coinData['additional_images'])) {
                            foreach ($coinData['additional_images'] as $imgData) {
                                $newFilename = $this->importImage($imgData['filename'], $tempDir);
                                if ($newFilename) {
                                    $coinImageModel->create([
                                        'coin_id' => $coinId,
                                        'filename' => $newFilename,
                                        'sort_order' => $imgData['sort_order'] ?? 0
                                    ]);
                                }
                            }
                        }
                    }
                } elseif (isset($subcollectionData['items'])) {
                    foreach ($subcollectionData['items'] as $itemData) {
                        $newObverse = $this->importImage($itemData['image_obverse'], $tempDir);
                        $newReverse = $this->importImage($itemData['image_reverse'], $tempDir);

                        $itemId = $itemModel->create([
                            'subcollection_id' => $subcollectionId,
                            'image_obverse' => $newObverse,
                            'image_reverse' => $newReverse,
                            'nominal_value' => $itemData['nominal_value'] ?? null,
                            'dimensions' => $itemData['dimensions'] ?? null,
                            'color' => $itemData['color'] ?? null,
                            'description_obverse' => $itemData['description_obverse'] ?? null,
                            'description_reverse' => $itemData['description_reverse'] ?? null,
                            'issue_date' => $itemData['issue_date'] ?? null,
                            'additional_info' => $itemData['additional_info'] ?? null,
                            'catalog_number' => $itemData['catalog_number'] ?? null,
                            'country' => $itemData['country'] ?? null,
                            'purchase_price' => $itemData['purchase_price'] ?? null,
                            'note' => $itemData['note'] ?? null,
                            'sort_order' => $itemData['sort_order'] ?? 0
                        ]);

                        // Import variants
                        if (isset($itemData['variants'])) {
                            foreach ($itemData['variants'] as $variantData) {
                                $variantModel->create([
                                    'item_id' => $itemId,
                                    'condition_id' => $variantData['condition_id'] ?? null,
                                    'variant_type_id' => $variantData['variant_type_id'] ?? null,
                                    'note' => $variantData['note'] ?? null,
                                    'owned' => $variantData['owned'] ?? 0,
                                    'sort_order' => $variantData['sort_order'] ?? 0
                                ]);
                            }
                        }

                        // Import additional item images
                        if (isset($itemData['additional_images'])) {
                            foreach ($itemData['additional_images'] as $imgData) {
                                $newFilename = $this->importImage($imgData['filename'], $tempDir);
                                if ($newFilename) {
                                    $itemImageModel->create([
                                        'item_id' => $itemId,
                                        'filename' => $newFilename,
                                        'sort_order' => $imgData['sort_order'] ?? 0
                                    ]);
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    private function importImage(?string $filename, string $tempDir): ?string
    {
        if (empty($filename)) {
            return null;
        }

        $sourcePath = $tempDir . '/images/' . $filename;
        if (!file_exists($sourcePath)) {
            return null;
        }

        $ext = pathinfo($filename, PATHINFO_EXTENSION);
        $newFilename = uniqid('img_', true) . '.' . $ext;
        $destPath = UPLOAD_ITEMS_PATH . '/' . $newFilename;

        if (copy($sourcePath, $destPath)) {
            return $newFilename;
        }

        return null;
    }

    private function cleanupTempDir(string $dir): void
    {
        if (is_dir($dir)) {
            $files = array_diff(scandir($dir), ['.', '..']);
            foreach ($files as $file) {
                $path = $dir . '/' . $file;
                if (is_dir($path)) {
                    $this->cleanupTempDir($path);
                } else {
                    unlink($path);
                }
            }
            rmdir($dir);
        }
    }
}
