<?php
namespace app\service;

use think\facade\Db;

class InstallService
{
    public function checkEnv(): array
    {
        $root    = root_path();
        $runtime = $root . 'runtime';

        // 服务器信息
        $server = [
            'os'              => PHP_OS,
            'server_software' => $_SERVER['SERVER_SOFTWARE'] ?? '',
            'php_version'     => PHP_VERSION,
            'install_path'    => $root . 'public',
            'disk_free'       => function_exists('disk_free_space') ? round(disk_free_space($root) / 1024 / 1024 / 1024, 2) . 'G' : '未知',
            'upload_limit'    => ini_get('upload_max_filesize') ?: '未配置',
        ];

        // PHP 环境要求
        $items = [];
        $passAll = true;

        // PHP 版本
        $phpOk = version_compare(PHP_VERSION, '8.0.0', '>=');
        $items[] = [
            'option'  => 'PHP版本',
            'require' => 'php8.0.0及以上',
            'status'  => '当前 ' . PHP_VERSION,
            'help'    => '建议使用PHP8.0版本',
            'pass'    => $phpOk,
        ];
        $passAll = $passAll && $phpOk;

        // 必须扩展
        $exts = [
            'pdo'       => '开启',
            'pdo_mysql' => '开启',
            'curl'      => '开启',
            'openssl'   => '开启',
            'fileinfo'  => '开启',
        ];

        foreach ($exts as $ext => $require) {
            $ok = extension_loaded($ext);
            $items[] = [
                'option'  => $ext . ' 扩展',
                'require' => $require,
                'status'  => $ok ? '已开启' : '未开启',
                'help'    => $ok ? '' : '请在 php.ini 中启用 ' . $ext . ' 扩展',
                'pass'    => $ok,
            ];
            $passAll = $passAll && $ok;
        }

        // 目录权限：public/storage、public/admin、config、runtime
        $dirs = [];

        $publicPath  = $root . 'public' . DIRECTORY_SEPARATOR;
        $storagePath = $publicPath . 'storage';
        $adminPath   = $publicPath . 'admin';
        $configPath  = $root . 'config';

        $checkDir = function (string $path, string $label) use (&$passAll) {
            $exists   = is_dir($path);
            $writable = $exists && is_writable($path);

            $status = $exists ? ($writable ? '可写' : '不可写') : '不存在';
            $help   = '';
            if (!$exists) {
                $help = '目录不存在，请创建目录并赋予可写权限';
            } elseif (!$writable) {
                $help = '目录不可写，请调整该目录的写入权限';
            }

            $pass = $exists && $writable;
            $passAll = $passAll && $pass;

            return [
                'path'    => $path,
                'require' => '可写',
                'status'  => $status,
                'pass'    => $pass,
            ];
        };

        $dirs[] = $checkDir($storagePath, 'public/storage');
        $dirs[] = $checkDir($adminPath, 'public/admin');
        $dirs[] = $checkDir($configPath, 'config');

        if (is_dir($runtime)) {
            $dirs[] = $checkDir($runtime, 'runtime');
        }

        return [
            'server'    => $server,
            'php_items' => $items,
            'dir_items' => $dirs,
            'pass'      => $passAll,
        ];
    }

    public function generateEnv(array $cfg): void
    {
        $envPath = root_path() . '.env';
        if (is_file($envPath)) {
            return;
        }

        $host   = $cfg['db_host'] ?? '127.0.0.1';
        $port   = $cfg['db_port'] ?? '3306';
        $name   = $cfg['db_name'] ?? '';
        $user   = $cfg['db_user'] ?? '';
        $pass   = $cfg['db_pass'] ?? '';
        $prefix = $cfg['db_prefix'] ?? 'wd_';

        if ($name === '' || $user === '') {
            throw new \Exception('数据库名/用户名不能为空');
        }

        $content  = "APP_DEBUG=false\n";
        $content .= "DB_HOST={$host}\n";
        $content .= "DB_PORT={$port}\n";
        $content .= "DB_NAME={$name}\n";
        $content .= "DB_USER={$user}\n";
        $content .= "DB_PASS={$pass}\n";
        $content .= "DB_PREFIX={$prefix}\n";

        if (@file_put_contents($envPath, $content) === false) {
            throw new \Exception('.env 写入失败，请检查项目根目录写权限');
        }
    }

    public function initDatabase(array $cfg): array
    {
        $host = $cfg['db_host'] ?? '127.0.0.1';
        $port = $cfg['db_port'] ?? '3306';
        $name = $cfg['db_name'] ?? '';
        $user = $cfg['db_user'] ?? '';
        $pass = $cfg['db_pass'] ?? '';
        $adminAccount = $cfg['admin_account'] ?? '';
        $adminName = $cfg['admin_name'] ?? $adminAccount;
        $adminPassword = $cfg['admin_password'] ?? '';

        if ($name === '' || $user === '') {
            throw new \Exception('数据库名/用户名不能为空');
        }

        if ($adminAccount === '' || $adminPassword === '') {
            throw new \Exception('管理员账号/密码不能为空');
        }

        // 1) 先用 PDO 建库
        $dsn = "mysql:host={$host};port={$port};charset=utf8mb4";
        $pdo = new \PDO($dsn, $user, $pass, [
            \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION
        ]);
        try {
            $pdo->exec("CREATE DATABASE IF NOT EXISTS `{$name}` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci");
        } catch (\PDOException $e) {
            if (strpos($e->getMessage(), 'Access denied') !== false) {
                throw new \Exception("数据库初始化失败：当前账号无权限创建数据库 '{$name}'，请检查权限或提前手动创建数据库。");
            }
            throw new \Exception("数据库初始化失败：" . $e->getMessage());
        }

        // 2) 导入初始化 SQL（确认你仓库里有这个文件）
        $sqlFile = root_path() . DIRECTORY_SEPARATOR.'public'.DIRECTORY_SEPARATOR.'install'.DIRECTORY_SEPARATOR.'sql'.DIRECTORY_SEPARATOR.'init_data.sql';
        if (!is_file($sqlFile)) {
            throw new \Exception("找不到初始化SQL：{$sqlFile}");
        }

        $conn = Db::connect([
            'type'     => 'mysql',
            'hostname' => $host,
            'hostport' => $port,
            'database' => $name,
            'username' => $user,
            'password' => $pass,
            'charset'  => 'utf8mb4',
        ]);

        $sql = file_get_contents($sqlFile);

        // 替换表前缀
        $prefix = $cfg['db_prefix'] ?? 'wd_';
        if ($prefix !== 'wd_') {
            $sql = str_replace("`wd_", "`{$prefix}", $sql);
        }

        $stmts = preg_split("/;\s*\n/", $sql);
        $tables = [];
        foreach ($stmts as $stmt) {
            $stmt = trim($stmt);
            if ($stmt === '') {
                continue;
            }

            $tableName = null;
            if (preg_match('/^CREATE\s+TABLE\s+(IF\s+NOT\s+EXISTS\s+)?`?(\w+)`?/i', $stmt, $m)) {
                $tableName = $m[2] ?? null;
            }

            $conn->execute($stmt);

            if ($tableName) {
                $tables[] = $tableName;
            }
        }

        // 初始化首个管理员账号
        $hashedPassword = password_hash($adminPassword, PASSWORD_BCRYPT);
        $now = time();
        
        // 使用配置的前缀
        $prefix = $cfg['db_prefix'] ?? 'wd_';
        $adminTable = $prefix . 'admin';

        // 先清理可能存在的 ID=1 记录，确保是插入
        try {
            $conn->execute("DELETE FROM `{$adminTable}` WHERE id = 1");
        } catch (\Throwable $e) {
            // 忽略删除错误
        }

        $conn->execute(
            "INSERT INTO `{$adminTable}` (`id`, `account`, `avatar`, `name`, `password`, `is_admin`, `create_time`, `update_time`) VALUES (1, ?, ?, ?, ?, 1, ?, ?)",
            [$adminAccount, 'static/admin/image/default_avatar.png', $adminName, $hashedPassword, $now, $now]
        );

        return [
            'database' => $name,
            'tables'   => $tables,
        ];
    }
    public function testDbConnection(array $cfg): void
    {
        $host = $cfg['db_host'] ?? '127.0.0.1';
        $port = $cfg['db_port'] ?? '3306';
        $user = $cfg['db_user'] ?? '';
        $pass = $cfg['db_pass'] ?? '';
        $name = $cfg['db_name'] ?? '';
        $prefix = $cfg['db_prefix'] ?? 'wd_';

        if ($user === '') {
            throw new \Exception('数据库用户名不能为空');
        }

        // 1. 尝试连接 MySQL Server
        $dsn = "mysql:host={$host};port={$port};charset=utf8mb4";
        try {
            $pdo = new \PDO($dsn, $user, $pass, [
                \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
                \PDO::ATTR_TIMEOUT => 5,
            ]);
        } catch (\PDOException $e) {
            $code = $e->getCode();
            $msg  = $e->getMessage();

            if ($code == 1045 || strpos($msg, 'Access denied') !== false) {
                throw new \Exception("数据库连接失败：用户名或密码错误，请检查数据库账号和密码。");
            }
            if ($code == 2002 || strpos($msg, 'Connection refused') !== false || strpos($msg, 'No such file or directory') !== false) {
                throw new \Exception("数据库连接失败：无法连接到数据库主机 {$host}:{$port}，请检查主机地址和端口。");
            }
            if ($code == 1049 || strpos($msg, 'Unknown database') !== false) {
                throw new \Exception("数据库连接失败：指定的数据库 '{$name}' 不存在。");
            }

            throw new \Exception("数据库连接失败：" . $msg);
        }

        // 2. 检查数据库是否存在
        if ($name) {
            // 查询数据库是否存在
            $stmt = $pdo->query("SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = '{$name}'");
            if ($stmt->fetch()) {
                // 数据库存在，检查关键表是否存在
                $pdo->exec("USE `{$name}`");
                // 检查 wd_admin 表是否存在 (使用前缀)
                $tableName = $prefix . 'admin';
                $stmt = $pdo->query("SHOW TABLES LIKE '{$tableName}'");
                if ($stmt->fetch()) {
                    throw new \Exception("数据表已存在，您之前可能已安装本系统，如需继续安装请选择新的数据库。");
                }
            } else {
                // 数据库不存在，尝试创建以验证权限
                try {
                    $pdo->exec("CREATE DATABASE IF NOT EXISTS `{$name}` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci");
                } catch (\PDOException $e) {
                    if (strpos($e->getMessage(), 'Access denied') !== false) {
                        throw new \Exception("数据库初始化失败：当前账号无权限创建数据库 '{$name}'，请检查权限或提前手动创建数据库。");
                    }
                    throw new \Exception("数据库创建测试失败：" . $e->getMessage());
                }
            }
        }
    }
}
