<?php
require_once __DIR__ . '/DomainRepository.php';
require_once __DIR__ . '/CloudflareConfig.php';
require_once __DIR__ . '/CloudflareClient.php';

/**
 * 域名添加 / NS 检测 / DNS+SSL 配置 / 删除编排
 */
class DomainProvisioningService
{
    /** @var CloudflareClient|null CLI 回归注入 Mock 客户端 */
    private static $clientOverride = null;

    public static function setClientOverride($client)
    {
        self::$clientOverride = $client;
    }

    public static function clearClientOverride()
    {
        self::$clientOverride = null;
    }

    private static function newClient()
    {
        return self::$clientOverride !== null ? self::$clientOverride : new CloudflareClient();
    }

    /**
     * 添加域名：本地入库 + 可选创建 Cloudflare Zone
     *
     * @return array{ok:bool,error?:string,hostname?:string,id?:int,nameservers?:array,cf_status?:string}
     */
    public static function provisionOnAdd(PDO $pdo, $hostname)
    {
        $add = DomainRepository::add($pdo, $hostname);
        if (!$add['ok']) {
            return $add;
        }

        $id   = (int) $add['id'];
        $host = $add['hostname'];

        if (!CloudflareConfig::isEnabled()) {
            DomainRepository::updateCloudflareMeta($pdo, $id, [
                'cf_status' => 'local',
            ]);
            return [
                'ok'        => true,
                'id'        => $id,
                'hostname'  => $host,
                'cf_status' => 'local',
                'nameservers' => [],
            ];
        }

        $client = self::newClient();
        $zone   = $client->createZone($host);
        if (!$zone['ok']) {
            DomainRepository::updateCloudflareMeta($pdo, $id, [
                'cf_status' => 'error',
                'cf_error'  => $zone['error'] ?? '创建 Zone 失败',
            ]);
            return [
                'ok'       => false,
                'error'    => $zone['error'] ?? 'Cloudflare 创建 Zone 失败',
                'id'       => $id,
                'hostname' => $host,
            ];
        }

        $result = $zone['result'];
        $ns     = is_array($result['name_servers'] ?? null) ? $result['name_servers'] : [];
        DomainRepository::updateCloudflareMeta($pdo, $id, [
            'cf_zone_id'     => (string) ($result['id'] ?? ''),
            'cf_nameservers' => json_encode($ns, JSON_UNESCAPED_UNICODE),
            'cf_status'      => 'pending_ns',
            'cf_error'       => '',
            'cf_checked_at'  => date('Y-m-d H:i:s'),
        ]);

        return [
            'ok'          => true,
            'id'          => $id,
            'hostname'    => $host,
            'cf_status'   => 'pending_ns',
            'nameservers' => $ns,
        ];
    }

    /**
     * 手动检测 NS 是否生效，生效后配置 A 记录与 SSL
     *
     * @return array{ok:bool,status?:string,message?:string,nameservers?:array}
     */
    public static function checkAndProvision(PDO $pdo, $domainId)
    {
        $row = DomainRepository::findById($pdo, $domainId);
        if (!$row) {
            return ['ok' => false, 'message' => '域名不存在'];
        }

        if (!CloudflareConfig::isEnabled()) {
            return ['ok' => false, 'message' => '未配置 Cloudflare API，无法检测'];
        }

        $client = self::newClient();
        $zoneId = trim((string) ($row['cf_zone_id'] ?? ''));

        if ($zoneId === '') {
            $zone = $client->createZone($row['hostname']);
            if (!$zone['ok']) {
                DomainRepository::updateCloudflareMeta($pdo, $domainId, [
                    'cf_status' => 'error',
                    'cf_error'  => $zone['error'] ?? '补创建 Zone 失败',
                    'cf_checked_at' => date('Y-m-d H:i:s'),
                ]);
                return ['ok' => false, 'message' => $zone['error'] ?? '补创建 Zone 失败'];
            }
            $result = $zone['result'];
            $zoneId = (string) ($result['id'] ?? '');
            $ns     = is_array($result['name_servers'] ?? null) ? $result['name_servers'] : [];
            DomainRepository::updateCloudflareMeta($pdo, $domainId, [
                'cf_zone_id'     => $zoneId,
                'cf_nameservers' => json_encode($ns, JSON_UNESCAPED_UNICODE),
                'cf_status'      => 'pending_ns',
                'cf_error'       => '',
                'cf_checked_at'  => date('Y-m-d H:i:s'),
            ]);
            $row = DomainRepository::findById($pdo, $domainId);
        }

        $zoneRes = $client->getZone($zoneId);
        if (!$zoneRes['ok']) {
            DomainRepository::updateCloudflareMeta($pdo, $domainId, [
                'cf_status' => 'error',
                'cf_error'  => $zoneRes['error'] ?? '读取 Zone 失败',
                'cf_checked_at' => date('Y-m-d H:i:s'),
            ]);
            return ['ok' => false, 'message' => $zoneRes['error'] ?? '读取 Zone 失败'];
        }

        $zoneData = $zoneRes['result'];
        $status   = strtolower((string) ($zoneData['status'] ?? 'pending'));
        $ns       = CloudflareConfig::parseNameservers($row['cf_nameservers'] ?? '');
        if (empty($ns) && is_array($zoneData['name_servers'] ?? null)) {
            $ns = $zoneData['name_servers'];
            DomainRepository::updateCloudflareMeta($pdo, $domainId, [
                'cf_nameservers' => json_encode($ns, JSON_UNESCAPED_UNICODE),
            ]);
        }

        if ($status !== 'active') {
            DomainRepository::updateCloudflareMeta($pdo, $domainId, [
                'cf_status'     => 'pending_ns',
                'cf_checked_at' => date('Y-m-d H:i:s'),
                'cf_error'      => '',
            ]);
            return [
                'ok'          => true,
                'status'      => 'pending_ns',
                'message'     => 'Nameserver 尚未生效，请到注册商修改为：' . implode('、', $ns),
                'nameservers' => $ns,
            ];
        }

        $serverIp = CloudflareConfig::serverIp();
        if ($serverIp === '') {
            DomainRepository::updateCloudflareMeta($pdo, $domainId, [
                'cf_status'     => 'error',
                'cf_error'      => 'SERVER_IP 未配置，无法添加 DNS 记录',
                'cf_checked_at' => date('Y-m-d H:i:s'),
            ]);
            return ['ok' => false, 'message' => 'SERVER_IP 未配置，请在 cong.php 中填写服务器公网 IP'];
        }

        DomainRepository::updateCloudflareMeta($pdo, $domainId, [
            'cf_status' => 'provisioning',
            'cf_error'  => '',
        ]);

        $host = $row['hostname'];
        foreach ([$host, 'www.' . $host] as $fqdn) {
            $dns = $client->upsertARecord($zoneId, $fqdn, $serverIp, true);
            if (!$dns['ok']) {
                DomainRepository::updateCloudflareMeta($pdo, $domainId, [
                    'cf_status' => 'error',
                    'cf_error'  => 'DNS 记录失败(' . $fqdn . '): ' . ($dns['error'] ?? ''),
                    'cf_checked_at' => date('Y-m-d H:i:s'),
                ]);
                return ['ok' => false, 'message' => $dns['error'] ?? 'DNS 配置失败'];
            }
        }

        $ssl = $client->setSslFlexible($zoneId);
        if (!$ssl['ok']) {
            DomainRepository::updateCloudflareMeta($pdo, $domainId, [
                'cf_status' => 'error',
                'cf_error'  => 'SSL Flexible 失败: ' . ($ssl['error'] ?? ''),
                'cf_checked_at' => date('Y-m-d H:i:s'),
            ]);
            return ['ok' => false, 'message' => $ssl['error'] ?? 'SSL 配置失败'];
        }

        $https = $client->setAlwaysHttps($zoneId);
        if (!$https['ok']) {
            DomainRepository::updateCloudflareMeta($pdo, $domainId, [
                'cf_status' => 'error',
                'cf_error'  => 'Always HTTPS 失败: ' . ($https['error'] ?? ''),
                'cf_checked_at' => date('Y-m-d H:i:s'),
            ]);
            return ['ok' => false, 'message' => $https['error'] ?? 'Always HTTPS 配置失败'];
        }

        DomainRepository::updateCloudflareMeta($pdo, $domainId, [
            'cf_status'     => 'ready',
            'cf_error'      => '',
            'cf_checked_at' => date('Y-m-d H:i:s'),
        ]);

        return [
            'ok'      => true,
            'status'  => 'ready',
            'message' => '域名已生效：A 记录(@/www) 已指向 ' . $serverIp . '，已开启 Flexible SSL 与 Always HTTPS',
            'nameservers' => $ns,
        ];
    }

    /**
     * 删除本地记录并尝试删除 Cloudflare Zone
     *
     * @return array{ok:bool,message?:string,warning?:string}
     */
    public static function deleteWithCloudflare(PDO $pdo, $domainId)
    {
        $row = DomainRepository::findById($pdo, $domainId);
        if (!$row) {
            return ['ok' => false, 'message' => '域名不存在'];
        }

        $warning = '';
        $zoneId  = trim((string) ($row['cf_zone_id'] ?? ''));
        if ($zoneId !== '' && CloudflareConfig::isEnabled()) {
            $del = self::newClient()->deleteZone($zoneId);
            if (!$del['ok']) {
                $warning = 'Cloudflare Zone 删除失败：' . ($del['error'] ?? '未知错误');
            }
        }

        DomainRepository::deleteById($pdo, $domainId);
        return [
            'ok'      => true,
            'message' => '域名已删除',
            'warning' => $warning,
        ];
    }
}
