<?php

declare(strict_types=1);

namespace App\Http\Controllers\Install;

use App\Http\Controllers\Controller;
use App\Http\Requests\Install\InstallDatabaseRequest;
use App\Services\Install\DatabaseConnectionTester;
use App\Services\Install\EnvironmentFileWriter;
use App\Services\Install\InstallerDatabaseConnectionException;
use App\Services\Install\InstallerDatabaseStateChecker;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\Artisan;
use JsonException;
use Throwable;

final class InstallDatabaseController extends Controller
{
    public function show(): View
    {
        return view('install.database', [
            'defaults' => [
                'db_connection' => old('db_connection', 'mysql'),
                'db_host' => old('db_host', '127.0.0.1'),
                'db_port' => old('db_port', '3306'),
                'db_database' => old('db_database', ''),
                'db_username' => old('db_username', ''),
            ],
        ]);
    }

    public function store(
        InstallDatabaseRequest $request,
        DatabaseConnectionTester $databaseConnectionTester,
        InstallerDatabaseStateChecker $installerDatabaseStateChecker,
        EnvironmentFileWriter $environmentFileWriter,
    ): RedirectResponse {
        $validated = $request->validated();

        try {
            $databaseConnectionTester->testMysqlFamily(
                (string) $validated['db_connection'],
                (string) $validated['db_host'],
                (int) $validated['db_port'],
                (string) $validated['db_database'],
                (string) $validated['db_username'],
                $validated['db_password'] ?? null,
                '',
            );
        } catch (InstallerDatabaseConnectionException $e) {
            return redirect()
                ->route('install.database')
                ->withInput($request->except('db_password'))
                ->withErrors(['connection' => $e->getMessage()]);
        } catch (Throwable) {
            return redirect()
                ->route('install.database')
                ->withInput($request->except('db_password'))
                ->withErrors(['connection' => '数据库连接失败，请核对连接信息后重试。']);
        }

        $databaseState = $installerDatabaseStateChecker->inspectMysqlFamily(
            (string) $validated['db_connection'],
            (string) $validated['db_host'],
            (int) $validated['db_port'],
            (string) $validated['db_database'],
            (string) $validated['db_username'],
            $validated['db_password'] ?? null,
            '',
        );

        $envValues = [
            'DB_CONNECTION' => (string) $validated['db_connection'],
            'DB_HOST' => (string) $validated['db_host'],
            'DB_PORT' => (string) (int) $validated['db_port'],
            'DB_DATABASE' => (string) $validated['db_database'],
            'DB_USERNAME' => (string) $validated['db_username'],
            'DB_PASSWORD' => (string) ($validated['db_password'] ?? ''),
            'DB_PREFIX' => '',
        ];

        try {
            $environmentFileWriter->mergeKeysIntoEnv(base_path(), $envValues);
        } catch (JsonException) {
            return redirect()
                ->route('install.database')
                ->withInput($request->except('db_password'))
                ->withErrors(['connection' => '安装配置保存失败，请检查程序目录写入权限后重试。']);
        } catch (Throwable) {
            return redirect()
                ->route('install.database')
                ->withInput($request->except('db_password'))
                ->withErrors(['connection' => '安装配置保存失败，请检查程序目录写入权限后重试。']);
        }

        // 仅清除基于文件的缓存，跳过 cache:clear（依赖数据库，迁移前表不存在）
        Artisan::call('config:clear');
        Artisan::call('route:clear');
        Artisan::call('view:clear');

        if (! $databaseState['safe']) {
            $hint = '数据库连接已保存。当前库中已有数据，无法直接全新安装。';
            if (($databaseState['checks']['reinstall_reset_supported'] ?? false) === true) {
                $hint .= ' 若仅用于测试且确认可清空，请在下一步勾选「重新安装」后继续。';
            } else {
                $hint .= ' 请更换专用空库，或联系技术人员处理后再继续。';
            }

            return redirect()
                ->route('install.initialize')
                ->with('status', $hint);
        }

        return redirect()
            ->route('install.initialize')
            ->with('status', '数据库配置已保存。请继续完成系统初始化并创建首任超级管理员。');
    }
}
