<?php
declare(strict_types=1);

namespace App\Modules\PublicArea;

use App\Core\AuditLogger;
use App\Core\Auth;
use App\Core\Database;
use App\Core\Request;
use App\Core\Settings;
use App\Core\Session;
use App\Core\View;

final class ClientPurchaseController
{
    public function index(Request $request): string
    {
        require_role('client');

        $userId = (int) (Auth::id() ?? 0);
        $selectedProductId = (int) $request->input('product_id', 0);

        $products = Database::query(
            'SELECT id, nama_produk, harga, deskripsi, status
             FROM products
             WHERE status = :status
             ORDER BY harga ASC, id ASC',
            [
                'status' => 'aktif',
            ]
        )->fetchAll();

        $purchases = Database::query(
            'SELECT p.id, p.harga, p.status, p.bukti_transfer, p.created_at, p.updated_at,
                    pr.nama_produk AS product_name
             FROM purchases p
             INNER JOIN products pr ON pr.id = p.product_id
             WHERE p.user_id = :user_id
             ORDER BY p.created_at DESC, p.id DESC',
            [
                'user_id' => $userId,
            ]
        )->fetchAll();

        $selectedProduct = null;
        if ($selectedProductId > 0) {
            $selectedProduct = Database::query(
                'SELECT id, nama_produk, harga, deskripsi, status
                 FROM products
                 WHERE id = :id AND status = :status
                 LIMIT 1',
                [
                    'id' => $selectedProductId,
                    'status' => 'aktif',
                ]
            )->fetch();
        }

        return View::renderTemplate('public/client/purchases', [
            'products' => $products,
            'purchases' => $purchases,
            'selectedProduct' => is_array($selectedProduct) ? $selectedProduct : null,
            'paymentSettings' => $this->paymentSettings(),
            'activeNav' => 'purchases',
        ], 'public/client/layout');
    }

    public function store(Request $request): never
    {
        require_role('client');
        verify_csrf((string) $request->input('_token', ''));

        $userId = (int) (Auth::id() ?? 0);
        $productId = (int) $request->input('product_id', 0);

        if ($productId <= 0) {
            Session::flash('errors', [
                'product_id' => ['Produk tidak valid.'],
            ]);
            redirect('/dashboard/purchases');
        }

        $product = Database::query(
            'SELECT id, nama_produk, harga, status
             FROM products
             WHERE id = :id
             LIMIT 1',
            [
                'id' => $productId,
            ]
        )->fetch();

        if (! is_array($product) || ($product['status'] ?? '') !== 'aktif') {
            Session::flash('errors', [
                'product_id' => ['Produk tidak ditemukan atau sedang nonaktif.'],
            ]);
            redirect('/dashboard/purchases');
        }

        $now = date('Y-m-d H:i:s');
        Database::query(
            'INSERT INTO purchases (user_id, product_id, harga, bukti_transfer, status, created_at, updated_at)
             VALUES (:user_id, :product_id, :harga, :bukti_transfer, :status, :created_at, :updated_at)',
            [
                'user_id' => $userId,
                'product_id' => $productId,
                'harga' => $product['harga'],
                'bukti_transfer' => null,
                'status' => 'pending',
                'created_at' => $now,
                'updated_at' => $now,
            ]
        );

        $purchaseId = (int) Database::connection()->lastInsertId();
        AuditLogger::log('client_purchase_create', $userId, [
            'purchase_id' => $purchaseId,
            'product_id' => $productId,
        ]);

        Session::flash('purchase_selected', [
            'product_name' => (string) $product['nama_produk'],
            'bank_account_number' => (string) Settings::get('bank_account_number', ''),
            'payment_barcode' => Settings::get('payment_barcode'),
        ]);
        redirect('/dashboard/status');
    }

    public function upload(Request $request): string
    {
        require_role('client');

        $userId = (int) (Auth::id() ?? 0);
        $pendingPurchases = Database::query(
            'SELECT p.id, p.harga, p.status, p.bukti_transfer, p.created_at, p.updated_at,
                    pr.nama_produk AS product_name
             FROM purchases p
             INNER JOIN products pr ON pr.id = p.product_id
             WHERE p.user_id = :user_id AND p.status = :status
             ORDER BY p.created_at DESC, p.id DESC',
            [
                'user_id' => $userId,
                'status' => 'pending',
            ]
        )->fetchAll();

        return View::renderTemplate('public/client/upload', [
            'pendingPurchases' => $pendingPurchases,
            'paymentSettings' => $this->paymentSettings(),
            'activeNav' => 'upload',
        ], 'public/client/layout');
    }

    public function uploadStore(Request $request): never
    {
        require_role('client');
        verify_csrf((string) $request->input('_token', ''));

        $userId = (int) (Auth::id() ?? 0);
        $purchaseId = (int) $request->input('purchase_id', 0);
        $purchase = $this->findPendingPurchase($purchaseId, $userId);

        if ($purchase === null) {
            Session::flash('errors', [
                'purchase_id' => ['Pembelian pending tidak ditemukan.'],
            ]);
            redirect('/dashboard/upload');
        }

        $file = $_FILES['bukti_transfer'] ?? null;
        if (! is_array($file)) {
            Session::flash('errors', [
                'bukti_transfer' => ['File bukti transfer wajib diunggah.'],
            ]);
            redirect('/dashboard/upload');
        }

        $uploadError = $this->validateProofFile($file);
        if ($uploadError !== null) {
            Session::flash('errors', [
                'bukti_transfer' => [$uploadError],
            ]);
            redirect('/dashboard/upload');
        }

        $storedPath = $this->storeProofFile($file);
        $now = date('Y-m-d H:i:s');

        Database::query(
            'UPDATE purchases
             SET bukti_transfer = :bukti_transfer,
                 updated_at = :updated_at
             WHERE id = :id AND user_id = :user_id',
            [
                'bukti_transfer' => $storedPath,
                'updated_at' => $now,
                'id' => $purchaseId,
                'user_id' => $userId,
            ]
        );

        AuditLogger::log('client_purchase_upload', $userId, [
            'purchase_id' => $purchaseId,
            'path' => $storedPath,
        ]);

        Session::flash('status', 'Bukti pembayaran berhasil diunggah. Mohon tunggu, admin sedang memverifikasi pembayaran dan menyiapkan proses instalasi jaringan di handphone Anda.');
        Session::flash('purchase_notice_title', 'Konfirmasi pembelian berhasil.');
        redirect('/dashboard/status');
    }

    public function status(Request $request): string
    {
        require_role('client');

        $userId = (int) (Auth::id() ?? 0);
        $statusFilter = (string) $request->input('status', 'all');
        $allowedFilters = ['all', 'active', 'inactive', 'pending', 'verified', 'completed', 'rejected'];
        if (! in_array($statusFilter, $allowedFilters, true)) {
            $statusFilter = 'all';
        }

        $latestPurchase = Database::query(
            'SELECT p.id, p.harga, p.status, p.bukti_transfer, p.created_at, p.updated_at,
                    pr.nama_produk AS product_name
             FROM purchases p
             INNER JOIN products pr ON pr.id = p.product_id
             WHERE p.user_id = :user_id
             ORDER BY p.created_at DESC, p.id DESC
             LIMIT 1',
            [
                'user_id' => $userId,
            ]
        )->fetch();

        $where = 'WHERE p.user_id = :user_id';
        $params = [
            'user_id' => $userId,
        ];

        if ($statusFilter === 'active') {
            $where .= ' AND p.status IN (:pending_status, :verified_status)';
            $params['pending_status'] = 'pending';
            $params['verified_status'] = 'verified';
        } elseif ($statusFilter === 'inactive') {
            $where .= ' AND p.status IN (:completed_status, :rejected_status)';
            $params['completed_status'] = 'completed';
            $params['rejected_status'] = 'rejected';
        } elseif ($statusFilter !== 'all') {
            $where .= ' AND p.status = :status';
            $params['status'] = $statusFilter;
        }

        $purchases = Database::query(
            'SELECT p.id, p.harga, p.status, p.bukti_transfer, p.created_at, p.updated_at,
                    pr.nama_produk AS product_name
             FROM purchases p
             INNER JOIN products pr ON pr.id = p.product_id
             ' . $where . '
             ORDER BY p.created_at DESC, p.id DESC',
            $params
        )->fetchAll();

        return View::renderTemplate('public/client/status', [
            'purchases' => $purchases,
            'latestPurchase' => is_array($latestPurchase) ? $latestPurchase : null,
            'statusFilter' => $statusFilter,
            'paymentSettings' => $this->paymentSettings(),
            'activeNav' => 'status',
        ], 'public/client/layout');
    }

    private function findPendingPurchase(int $purchaseId, int $userId): ?array
    {
        if ($purchaseId <= 0) {
            return null;
        }

        $purchase = Database::query(
            'SELECT id, status, bukti_transfer
             FROM purchases
             WHERE id = :id AND user_id = :user_id AND status = :status
             LIMIT 1',
            [
                'id' => $purchaseId,
                'user_id' => $userId,
                'status' => 'pending',
            ]
        )->fetch();

        return is_array($purchase) ? $purchase : null;
    }

    private function validateProofFile(array $file): ?string
    {
        $error = (int) ($file['error'] ?? UPLOAD_ERR_NO_FILE);
        if ($error !== UPLOAD_ERR_OK) {
            return 'File bukti transfer wajib diunggah.';
        }

        $tmpName = (string) ($file['tmp_name'] ?? '');
        if ($tmpName === '' || ! is_uploaded_file($tmpName)) {
            return 'File upload tidak valid.';
        }

        $size = (int) ($file['size'] ?? 0);
        if ($size <= 0) {
            return 'File bukti transfer tidak boleh kosong.';
        }

        if ($size > 5 * 1024 * 1024) {
            return 'Ukuran file maksimal 5 MB.';
        }

        $originalName = (string) ($file['name'] ?? '');
        $extension = strtolower(pathinfo($originalName, PATHINFO_EXTENSION));
        $allowed = [
            'jpg' => ['image/jpeg', 'image/pjpeg'],
            'jpeg' => ['image/jpeg', 'image/pjpeg'],
            'png' => ['image/png'],
            'pdf' => ['application/pdf'],
        ];

        if (! isset($allowed[$extension])) {
            return 'Format file hanya boleh JPG, PNG, atau PDF.';
        }

        $finfo = finfo_open(FILEINFO_MIME_TYPE);
        if ($finfo === false) {
            return 'Tidak dapat memeriksa tipe file.';
        }

        $mime = finfo_file($finfo, $tmpName);
        finfo_close($finfo);

        if (! is_string($mime) || ! in_array($mime, $allowed[$extension], true)) {
            return 'Tipe file bukti transfer tidak valid.';
        }

        return null;
    }

    private function storeProofFile(array $file): string
    {
        $originalName = (string) ($file['name'] ?? '');
        $extension = strtolower(pathinfo($originalName, PATHINFO_EXTENSION));
        if ($extension === 'jpeg') {
            $extension = 'jpg';
        }

        $directory = dirname(__DIR__, 3) . '/storage/uploads';
        if (! is_dir($directory)) {
            mkdir($directory, 0775, true);
        }

        $filename = 'proof-' . bin2hex(random_bytes(16)) . '.' . $extension;
        $targetPath = $directory . '/' . $filename;

        if (! move_uploaded_file((string) $file['tmp_name'], $targetPath)) {
            abort(500, 'Gagal menyimpan file upload.');
        }

        return 'storage/uploads/' . $filename;
    }

    private function paymentSettings(): array
    {
        return [
            'company_name' => (string) Settings::get('company_name', app_name()),
            'bank_account_number' => (string) Settings::get('bank_account_number', ''),
            'payment_barcode' => Settings::get('payment_barcode'),
        ];
    }
}
