<?php
namespace App\Controllers;

use App\Core\Controller;
use App\Models\HistoryModel;
use App\Models\KeyModel;
use App\Models\UserModel;

class KeysController extends Controller
{
    private array $defaultPrices = [];

    public function __construct()
    {
        parent::__construct();

        $cfg = app_config();
        $this->defaultPrices = app_normalize_key_prices($cfg['key_prices'] ?? []);
    }

    public function index(): void
    {
        $this->requireLogin();

        $isAdmin = $this->isAdminUser();
        $filters = $this->readFilters();
        $model = new KeyModel();
        $games = $this->gameCatalog();

        $keys = $model->listForUser((int)$this->user['id'], $isAdmin, $filters);
        $batchSummaries = $model->listBatchSummariesForUser((int)$this->user['id'], $isAdmin, $filters, 20);

        view('keys/list', [
            'title' => app_zh('卡密列表'),
            'user' => $this->user,
            'keys' => $keys,
            'filters' => $filters,
            'game_catalog' => $games,
            'batch_summaries' => $batchSummaries,
            'generated_batch' => flash('generated_batch'),
            'export_all_url' => app_url_with_query(base_url('keys/export-all'), $filters),
            'can_manage_keys' => $isAdmin,
        ]);
    }

    public function generate(): void
    {
        $this->requireLogin();

        $games = $this->gameCatalog();
        $defaultGameCode = (string)array_key_first($games);
        if ($defaultGameCode === '') {
            $defaultGameCode = 'PUBG';
        }

        view('keys/generate', [
            'title' => app_zh('生成卡密'),
            'user' => $this->user,
            'game_catalog' => $games,
            'default_game_code' => $defaultGameCode,
        ]);
    }

    public function generatePost(): void
    {
        $this->requireLogin();
        if (!verify_csrf()) {
            flash('error', app_zh('安全校验失败'));
            redirect('keys/generate');
        }

        $input = app_request_data();
        $game = app_clean_text((string)($input['game'] ?? ''), 64);
        $duration = (int)($input['duration'] ?? 0);
        $maxDevices = (int)($input['max_devices'] ?? 0);
        $customKey = app_clean_text((string)($input['custom_key'] ?? ''), 64);
        $quantity = (int)($input['quantity'] ?? 1);
        $prefix = app_clean_text((string)($input['prefix'] ?? ''), 20);
        $batchCode = strtoupper((string)preg_replace('/[^A-Za-z0-9_-]/', '', app_clean_text((string)($input['batch_code'] ?? ''), 40)));
        $batchName = app_clean_text((string)($input['batch_name'] ?? ''), 120);

        $games = $this->gameCatalog();
        if (!$games) {
            flash('error', app_zh('未配置可用游戏'));
            redirect('keys/generate');
        }
        if (!isset($games[$game])) {
            flash('error', app_zh('游戏参数错误'));
            redirect('keys/generate');
        }

        $gamePrices = $this->pricesForGame($game);
        if ($duration < 1 || !isset($gamePrices[$duration])) {
            flash('error', app_zh('时长不合法或当前游戏未配置该时长价格'));
            redirect('keys/generate');
        }

        if ($maxDevices < 1 || $maxDevices > 1000) {
            flash('error', app_zh('设备上限必须在 1 到 1000 之间'));
            redirect('keys/generate');
        }

        if ($quantity < 1) {
            $quantity = 1;
        }
        if ($quantity > 500) {
            flash('error', app_zh('单次最多生成 500 张卡密'));
            redirect('keys/generate');
        }

        if ($batchCode !== '' && !preg_match('/^[A-Za-z0-9_-]{1,40}$/', $batchCode)) {
            flash('error', app_zh('批次号格式不正确，仅支持 1-40 位字母、数字、下划线和中划线'));
            redirect('keys/generate');
        }

        $batchNameLen = function_exists('mb_strlen') ? mb_strlen($batchName, 'UTF-8') : strlen($batchName);
        if ($batchName !== '' && $batchNameLen > 120) {
            flash('error', app_zh('批次名称最多 120 个字符'));
            redirect('keys/generate');
        }

        if ($prefix !== '' && !preg_match('/^[A-Za-z0-9_-]{1,20}$/', $prefix)) {
            flash('error', app_zh('前缀格式不正确，仅支持 1-20 位字母、数字、下划线和中划线'));
            redirect('keys/generate');
        }

        if ($customKey !== '') {
            if ($quantity > 1) {
                flash('error', app_zh('批量生成时不能使用自定义完整卡密'));
                redirect('keys/generate');
            }
            if (!preg_match('/^[A-Za-z0-9_-]{6,64}$/', $customKey)) {
                flash('error', app_zh('自定义卡密格式不正确，仅支持 6-64 位字母、数字、下划线和中划线'));
                redirect('keys/generate');
            }
            if ((new KeyModel())->findByUserKey($customKey)) {
                flash('error', app_zh('自定义卡密已存在'));
                redirect('keys/generate');
            }
        }

        $unitPrice = (float)($gamePrices[$duration] ?? 0);
        $isAdmin = (($this->user['role'] ?? '') === 'admin');
        if (!$isAdmin && $unitPrice <= 0) {
            flash('error', app_zh('当前游戏的该时长未设置价格，代理无法生成'));
            redirect('keys/generate');
        }

        $fee = $isAdmin ? 0 : ($unitPrice * $maxDevices * $quantity);
        if (!$isAdmin) {
            $currentBalance = (float)($this->user['balance'] ?? 0);
            if ($fee > $currentBalance) {
                flash('error', app_zh('余额不足，需要扣费：') . $fee . app_zh('，当前余额：') . $currentBalance);
                redirect('keys/generate');
            }
        }

        $keyModel = new KeyModel();
        $generatedKeys = [];
        $randomLen = max(6, 16 - strlen($prefix));
        $batchName = $batchCode !== '' && $batchName !== '' ? $batchName : '';

        if ($customKey !== '') {
            $generatedKeys[] = $customKey;
        } else {
            for ($i = 0; $i < $quantity; $i++) {
                $tries = 0;
                do {
                    $candidate = $prefix . random_string($randomLen);
                    $tries++;
                } while ($keyModel->findByUserKey($candidate) && $tries < 10);

                if ($keyModel->findByUserKey($candidate)) {
                    flash('error', app_zh('生成卡密冲突，请重试'));
                    redirect('keys/generate');
                }

                $generatedKeys[] = $candidate;
            }
        }

        foreach ($generatedKeys as $generatedKey) {
            $keyId = $keyModel->create([
                'game' => $game,
                'batch_code' => $batchCode !== '' ? $batchCode : null,
                'batch_name' => $batchName !== '' ? $batchName : null,
                'user_key' => $generatedKey,
                'duration_hours' => $duration,
                'max_devices' => $maxDevices,
                'registrator_id' => (int)$this->user['id'],
            ]);

            $historyMessage = $game . '|' . substr($generatedKey, 0, 6) . '|' . $duration . '|' . $maxDevices;
            if ($batchCode !== '') {
                $historyMessage .= '|batch:' . $batchCode;
            }
            (new HistoryModel())->add(
                $keyId,
                (int)$this->user['id'],
                $historyMessage
            );
        }

        if (!$isAdmin) {
            $newBalance = (float)$this->user['balance'] - $fee;
            (new UserModel())->update((int)$this->user['id'], ['balance' => $newBalance]);
        }

        $_SESSION['last_generated_keys'] = $generatedKeys;
        $_SESSION['last_generated_batch'] = $batchCode !== '' ? [
            'code' => $batchCode,
            'name' => $batchName,
            'game' => $game,
            'game_name' => (string)($games[$game]['name'] ?? $game),
            'count' => count($generatedKeys),
        ] : [];

        flash('generated_keys', $generatedKeys);
        flash('generated_batch', $_SESSION['last_generated_batch']);

        $message = count($generatedKeys) === 1
            ? app_zh('生成成功：') . $generatedKeys[0]
            : app_zh('批量生成成功，共 ') . count($generatedKeys) . app_zh(' 张');
        if ($batchCode !== '') {
            $message .= app_zh('，批次号：') . $batchCode;
        }
        if (!$isAdmin) {
            $message .= app_zh('，扣费：') . $fee;
        }
        flash('success', $message);

        redirect('keys');
    }

    public function edit($id): void
    {
        $this->requireLogin();
        if ($this->denyIfKeyMutationForbidden()) {
            return;
        }

        $model = new KeyModel();
        $key = $model->findById((int)$id);
        if (!$key) {
            flash('error', app_zh('卡密不存在'));
            redirect('keys');
        }
        if (($this->user['role'] ?? '') !== 'admin' && (int)$key['registrator_id'] !== (int)$this->user['id']) {
            flash('error', app_zh('无权限操作'));
            redirect('keys');
        }

        view('keys/edit', [
            'title' => app_zh('编辑卡密'),
            'user' => $this->user,
            'key' => $key,
            'game_catalog' => $this->gameCatalog(),
        ]);
    }

    public function editPost($id): void
    {
        $this->requireLogin();
        if ($this->denyIfKeyMutationForbidden()) {
            return;
        }
        if (!verify_csrf()) {
            flash('error', app_zh('安全校验失败'));
            redirect('keys');
        }

        $model = new KeyModel();
        $key = $model->findById((int)$id);
        if (!$key) {
            flash('error', app_zh('卡密不存在'));
            redirect('keys');
        }
        if (($this->user['role'] ?? '') !== 'admin' && (int)$key['registrator_id'] !== (int)$this->user['id']) {
            flash('error', app_zh('无权限操作'));
            redirect('keys');
        }

        $input = app_request_data();
        $status = (($input['status'] ?? 'inactive') === 'active') ? 'active' : 'inactive';
        $data = ['status' => $status];

        if (($this->user['role'] ?? '') === 'admin') {
            $game = app_clean_text((string)($input['game'] ?? $key['game']), 64);
            $userKey = app_clean_text((string)($input['user_key'] ?? $key['user_key']), 64);
            $durationHours = (int)($input['duration_hours'] ?? $key['duration_hours']);
            $maxDevices = (int)($input['max_devices'] ?? $key['max_devices']);
            $batchCode = strtoupper((string)preg_replace('/[^A-Za-z0-9_-]/', '', app_clean_text((string)($input['batch_code'] ?? ($key['batch_code'] ?? '')), 40)));
            $batchName = app_clean_text((string)($input['batch_name'] ?? ($key['batch_name'] ?? '')), 120);
            $expiredAtRaw = app_clean_text((string)($input['expired_at'] ?? ''), 32);

            $games = $this->gameCatalog();
            if (!isset($games[$game])) {
                flash('error', app_zh('游戏不存在'));
                redirect('keys/edit/' . $id);
            }

            if (!preg_match('/^[A-Za-z0-9_-]{6,64}$/', $userKey)) {
                flash('error', app_zh('卡密格式不正确'));
                redirect('keys/edit/' . $id);
            }

            $duplicate = $model->findByUserKey($userKey);
            if ($duplicate && (int)$duplicate['id'] !== (int)$key['id']) {
                flash('error', app_zh('卡密已存在'));
                redirect('keys/edit/' . $id);
            }

            if ($durationHours < 1 || $durationHours > 24 * 365 * 10) {
                flash('error', app_zh('时长不合法'));
                redirect('keys/edit/' . $id);
            }

            if ($maxDevices < 1 || $maxDevices > 1000) {
                flash('error', app_zh('设备上限必须在 1 到 1000 之间'));
                redirect('keys/edit/' . $id);
            }

            if ($batchCode !== '' && strlen($batchCode) > 40) {
                flash('error', app_zh('批次号过长'));
                redirect('keys/edit/' . $id);
            }

            $batchNameLen = function_exists('mb_strlen') ? mb_strlen($batchName, 'UTF-8') : strlen($batchName);
            if ($batchName !== '' && $batchNameLen > 120) {
                flash('error', app_zh('批次名称最多 120 个字符'));
                redirect('keys/edit/' . $id);
            }

            $expiredAt = null;
            if ($expiredAtRaw !== '') {
                try {
                    $expiredAt = (new \DateTimeImmutable($expiredAtRaw))->format('Y-m-d H:i:s');
                } catch (\Throwable $e) {
                    flash('error', app_zh('到期时间格式错误，请使用 YYYY-MM-DD HH:MM:SS'));
                    redirect('keys/edit/' . $id);
                }
            }

            $data['game'] = $game;
            $data['user_key'] = $userKey;
            $data['duration_hours'] = $durationHours;
            $data['max_devices'] = $maxDevices;
            $data['batch_code'] = $batchCode !== '' ? $batchCode : null;
            $data['batch_name'] = $batchName !== '' ? $batchName : null;
            $data['expired_at'] = $expiredAt;
        }

        $model->update((int)$id, $data);
        flash('success', app_zh('卡密已更新'));
        redirect('keys');
    }

    public function resetDevices(): void
    {
        $this->requireLogin();
        if ($this->denyIfKeyMutationForbidden()) {
            return;
        }
        if (!verify_csrf()) {
            flash('error', app_zh('安全校验失败'));
            redirect('keys');
        }

        $input = app_request_data();
        $id = (int)($input['id'] ?? 0);
        $model = new KeyModel();
        $key = $model->findById($id);
        if (!$key) {
            flash('error', app_zh('卡密不存在'));
            redirect('keys');
        }
        if (($this->user['role'] ?? '') !== 'admin' && (int)$key['registrator_id'] !== (int)$this->user['id']) {
            flash('error', app_zh('无权限操作'));
            redirect('keys');
        }

        $model->update($id, ['devices' => null]);
        flash('success', app_zh('设备已清空'));
        redirect('keys');
    }

    public function delete(): void
    {
        $this->requireLogin();
        if ($this->denyIfKeyMutationForbidden()) {
            return;
        }
        if (!verify_csrf()) {
            flash('error', app_zh('安全校验失败'));
            redirect('keys');
        }

        $input = app_request_data();
        $id = (int)($input['id'] ?? 0);
        if ($id <= 0) {
            flash('error', app_zh('参数错误'));
            redirect('keys');
        }

        $isAdmin = (($this->user['role'] ?? '') === 'admin');
        $ok = (new KeyModel())->deleteByIdForUser($id, (int)$this->user['id'], $isAdmin);
        if ($ok) {
            flash('success', app_zh('卡密已删除'));
        } else {
            flash('error', app_zh('卡密不存在或无权限'));
        }
        redirect('keys');
    }

    public function deleteBatch(): void
    {
        $this->requireLogin();
        if ($this->denyIfKeyMutationForbidden()) {
            return;
        }
        if (!verify_csrf()) {
            flash('error', app_zh('安全校验失败'));
            redirect('keys');
        }

        $input = app_request_data();
        $ids = $input['ids'] ?? [];
        if (!is_array($ids) || !$ids) {
            flash('error', app_zh('请选择要删除的卡密'));
            redirect('keys');
        }

        $isAdmin = (($this->user['role'] ?? '') === 'admin');
        $count = (new KeyModel())->deleteByIdsForUser($ids, (int)$this->user['id'], $isAdmin);
        if ($count > 0) {
            flash('success', app_zh('已删除 ') . $count . app_zh(' 张卡密'));
        } else {
            flash('error', app_zh('没有可删除的卡密'));
        }
        redirect('keys');
    }

    public function batchUpdate(): void
    {
        $this->requireLogin();
        if ($this->denyIfKeyMutationForbidden()) {
            return;
        }
        if (!verify_csrf()) {
            flash('error', app_zh('安全校验失败'));
            redirect('keys');
        }

        $input = app_request_data();
        $ids = $input['ids'] ?? [];
        if (!is_array($ids) || !$ids) {
            flash('error', app_zh('请先选择卡密'));
            redirect('keys');
        }

        $action = app_clean_text((string)($input['batch_action'] ?? ''), 64);
        $isAdmin = (($this->user['role'] ?? '') === 'admin');
        $model = new KeyModel();
        $updated = 0;

        $idList = array_values(array_unique(array_filter(array_map('intval', $ids), static function ($v) {
            return $v > 0;
        })));
        if ($idList === []) {
            flash('error', app_zh('卡密参数错误'));
            redirect('keys');
        }

        foreach ($idList as $id) {
            $key = $model->findById((int)$id);
            if (!$key) {
                continue;
            }
            if (!$isAdmin && (int)$key['registrator_id'] !== (int)$this->user['id']) {
                continue;
            }

            $data = [];
            if ($action === 'status_active') {
                $data['status'] = 'active';
            } elseif ($action === 'status_inactive') {
                $data['status'] = 'inactive';
            } elseif ($action === 'set_max_devices') {
                $maxDevices = (int)($input['batch_max_devices'] ?? 0);
                if ($maxDevices < 1 || $maxDevices > 1000) {
                    flash('error', app_zh('设备上限必须在 1 到 1000 之间'));
                    redirect('keys');
                }
                $data['max_devices'] = $maxDevices;
            } elseif ($action === 'extend_hours') {
                $hours = (int)($input['batch_extend_hours'] ?? 0);
                if ($hours < 1 || $hours > 24 * 365) {
                    flash('error', app_zh('延期时长必须在 1 到 8760 小时之间'));
                    redirect('keys');
                }

                $base = trim((string)($key['expired_at'] ?? ''));
                if ($base === '') {
                    $baseTime = new \DateTimeImmutable('now');
                } else {
                    $exp = new \DateTimeImmutable($base);
                    $now = new \DateTimeImmutable('now');
                    $baseTime = $exp > $now ? $exp : $now;
                }
                $data['expired_at'] = $baseTime->modify('+' . $hours . ' hours')->format('Y-m-d H:i:s');
            } elseif ($action === 'set_batch_name') {
                $batchName = app_clean_text((string)($input['batch_rename'] ?? ''), 120);
                if ($batchName === '') {
                    flash('error', app_zh('请输入批次名称'));
                    redirect('keys');
                }
                $batchNameLen = function_exists('mb_strlen') ? mb_strlen($batchName, 'UTF-8') : strlen($batchName);
                if ($batchNameLen > 120) {
                    flash('error', app_zh('批次名称最多 120 个字符'));
                    redirect('keys');
                }
                $data['batch_name'] = $batchName;
            } elseif ($action === 'reset_devices') {
                $data['devices'] = null;
            } else {
                flash('error', app_zh('批量操作类型错误'));
                redirect('keys');
            }

            if ($data !== [] && $model->update((int)$id, $data)) {
                $updated++;
            }
        }

        if ($updated > 0) {
            flash('success', app_zh('批量操作完成，共影响 ') . $updated . app_zh(' 张卡密'));
        } else {
            flash('error', app_zh('没有卡密被更新'));
        }
        redirect('keys');
    }

    public function downloadLast(): void
    {
        $this->requireLogin();
        $keys = $_SESSION['last_generated_keys'] ?? [];
        if (!$keys) {
            flash('error', app_zh('没有可下载的卡密记录'));
            redirect('keys');
        }

        $batch = $_SESSION['last_generated_batch'] ?? [];
        $filenamePrefix = trim((string)($batch['code'] ?? ''));
        if ($filenamePrefix === '') {
            $filenamePrefix = date('Ymd_His');
        }

        $content = implode("\n", $keys) . "\n";
        header('Content-Type: text/plain; charset=utf-8');
        header('Content-Disposition: attachment; filename="' . $filenamePrefix . '.txt"');
        header('Content-Length: ' . strlen($content));
        echo $content;

        unset($_SESSION['last_generated_keys'], $_SESSION['last_generated_batch']);
        exit;
    }

    public function exportAll(): void
    {
        $this->requireLogin();

        $isAdmin = (($this->user['role'] ?? '') === 'admin');
        $filters = $this->readFilters();
        $keys = (new KeyModel())->listForUser((int)$this->user['id'], $isAdmin, $filters);

        $lines = [];
        foreach ($keys as $key) {
            $userKey = trim((string)($key['user_key'] ?? ''));
            if ($userKey !== '') {
                $lines[] = $userKey;
            }
        }

        $content = implode("\n", $lines) . "\n";
        header('Content-Type: text/plain; charset=utf-8');
        header('Content-Disposition: attachment; filename="' . date('Ymd_His') . '.txt"');
        header('Content-Length: ' . strlen($content));
        echo $content;
        exit;
    }

    private function pricesForGame(string $game): array
    {
        $row = $this->gameCatalog()[$game] ?? null;
        if (is_array($row) && !empty($row['prices']) && is_array($row['prices'])) {
            return app_normalize_key_prices($row['prices']);
        }
        return $this->defaultPrices;
    }

    private function gameCatalog(): array
    {
        return app_game_catalog();
    }

    private function readFilters(): array
    {
        $input = app_request_data();
        $status = app_clean_text((string)($input['status'] ?? ''), 32);
        if (!in_array($status, ['', 'active', 'inactive'], true)) {
            $status = '';
        }

        return [
            'game' => app_clean_text((string)($input['game'] ?? ''), 64),
            'batch' => app_clean_text((string)($input['batch'] ?? ''), 64),
            'keyword' => app_clean_text((string)($input['keyword'] ?? ''), 128),
            'status' => $status,
        ];
    }

    private function isAdminUser(): bool
    {
        return (($this->user['role'] ?? '') === 'admin');
    }

    private function denyIfKeyMutationForbidden(): bool
    {
        if ($this->isAdminUser()) {
            return false;
        }

        flash('error', app_zh('代理仅可生成、复制和导出卡密，不可修改、封禁、删除或清理设备'));
        redirect('keys');
        return true;
    }
}
