<?php
/**
 * 邮箱验证码验证类
 * 处理邮箱验证码的发送、存储和验证
 */
namespace lib;

class EmailVerify {
    private $DB;
    private $emailSender;
    private $codeLength = 6;
    private $expireTime = 600;
    private $sendInterval = 60;
    private $dailyLimit = 10;
    
    /**
     * 构造函数
     */
    public function __construct() {
        global $DB;
        $this->DB = $DB;
        $this->emailSender = new EmailSender();
    }
    
    /**
     * 生成验证码
     */
    private function generateCode() {
        return str_pad((string)mt_rand(0, 999999), $this->codeLength, '0', STR_PAD_LEFT);
    }
    
    /**
     * 发送验证码
     * @param string $email 邮箱地址
     * @param string $type 验证码类型 (bind/unbind/register/resetpwd)
     * @param int $uid 用户ID
     * @return array
     */
    public function sendCode($email, $type, $uid = 0) {
        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            return ['code' => -1, 'msg' => '邮箱格式不正确'];
        }
        
        if (!$this->emailSender->isReady()) {
            return ['code' => -1, 'msg' => '邮件服务未配置或未启用'];
        }
        
        $allowedTypes = ['bind', 'unbind', 'register', 'resetpwd'];
        if (!in_array($type, $allowedTypes)) {
            return ['code' => -1, 'msg' => '无效的验证码类型'];
        }
        
        $clientIp = $this->getClientIp();
        
        if ($this->isSendingTooFrequent($email, $clientIp)) {
            $remaining = $this->getRemainingTime($email, $clientIp);
            return ['code' => -1, 'msg' => "发送过于频繁，请{$remaining}秒后再试"];
        }
        
        if ($this->isDailyLimitReached($email, $clientIp)) {
            return ['code' => -1, 'msg' => '今日发送次数已达上限，请明天再试'];
        }
        
        $code = $this->generateCode();
        $expireAt = date('Y-m-d H:i:s', time() + $this->expireTime);
        
        try {
            $this->DB->exec(
                "INSERT INTO pre_email_verify (email, code, type, uid, ip, expire_at, created_at) 
                 VALUES (:email, :code, :type, :uid, :ip, :expire_at, NOW())",
                [
                    ':email' => $email,
                    ':code' => $code,
                    ':type' => $type,
                    ':uid' => $uid,
                    ':ip' => $clientIp,
                    ':expire_at' => $expireAt
                ]
            );
            
            $sendResult = $this->emailSender->sendVerifyCode($email, $code, $type);
            
            if ($sendResult) {
                return ['code' => 0, 'msg' => '验证码已发送，请查收邮件'];
            } else {
                return ['code' => -1, 'msg' => '邮件发送失败：' . $this->emailSender->getError()];
            }
        } catch (\Exception $e) {
            return ['code' => -1, 'msg' => '发送失败：' . $e->getMessage()];
        }
    }
    
    /**
     * 验证验证码
     * @param string $email 邮箱地址
     * @param string $code 验证码
     * @param string $type 验证码类型
     * @param int $uid 用户ID
     * @return array
     */
    public function verifyCode($email, $code, $type, $uid = 0) {
        if (empty($email) || empty($code)) {
            return ['code' => -1, 'msg' => '请填写完整信息'];
        }
        
        try {
            $record = $this->DB->getRow(
                "SELECT * FROM pre_email_verify 
                 WHERE email = :email AND code = :code AND type = :type AND uid = :uid AND is_used = 0 
                 ORDER BY id DESC LIMIT 1",
                [
                    ':email' => $email,
                    ':code' => $code,
                    ':type' => $type,
                    ':uid' => $uid
                ]
            );
            
            if (!$record) {
                return ['code' => -1, 'msg' => '验证码错误或已失效'];
            }
            
            if (strtotime($record['expire_at']) < time()) {
                return ['code' => -1, 'msg' => '验证码已过期，请重新获取'];
            }
            
            $this->DB->exec(
                "UPDATE pre_email_verify SET is_used = 1, used_at = NOW() WHERE id = :id",
                [':id' => $record['id']]
            );
            
            return ['code' => 0, 'msg' => '验证成功'];
        } catch (\Exception $e) {
            return ['code' => -1, 'msg' => '验证失败：' . $e->getMessage()];
        }
    }
    
    /**
     * 检查邮箱是否已被其他用户绑定
     * @param string $email 邮箱地址
     * @param int $excludeUid 排除的用户ID
     * @return bool
     */
    public function isEmailBoundByOther($email, $excludeUid = 0) {
        try {
            $user = $this->DB->getRow(
                "SELECT uid FROM pre_user WHERE email = :email AND uid != :uid LIMIT 1",
                [
                    ':email' => $email,
                    ':uid' => $excludeUid
                ]
            );
            return $user !== false;
        } catch (\Exception $e) {
            return false;
        }
    }
    
    /**
     * 检查邮箱是否已被注册
     * @param string $email 邮箱地址
     * @return bool
     */
    public function isEmailRegistered($email) {
        try {
            $count = $this->DB->getColumn(
                "SELECT COUNT(*) FROM pre_user WHERE email = :email LIMIT 1",
                [':email' => $email]
            );
            return $count > 0;
        } catch (\Exception $e) {
            return false;
        }
    }
    
    /**
     * 检查发送是否过于频繁
     */
    private function isSendingTooFrequent($email, $clientIp) {
        try {
            $lastSend = $this->DB->getRow(
                "SELECT created_at FROM pre_email_verify 
                 WHERE (email = :email OR ip = :ip) 
                 AND created_at > DATE_SUB(NOW(), INTERVAL :interval SECOND)
                 ORDER BY id DESC LIMIT 1",
                [
                    ':email' => $email,
                    ':ip' => $clientIp,
                    ':interval' => $this->sendInterval
                ]
            );
            return $lastSend !== false;
        } catch (\Exception $e) {
            return false;
        }
    }
    
    /**
     * 获取剩余等待时间
     */
    private function getRemainingTime($email, $clientIp) {
        try {
            $lastSend = $this->DB->getRow(
                "SELECT UNIX_TIMESTAMP(created_at) as send_time FROM pre_email_verify 
                 WHERE (email = :email OR ip = :ip) 
                 ORDER BY id DESC LIMIT 1",
                [
                    ':email' => $email,
                    ':ip' => $clientIp
                ]
            );
            
            if ($lastSend) {
                $elapsed = time() - $lastSend['send_time'];
                return max(0, $this->sendInterval - $elapsed);
            }
            return 0;
        } catch (\Exception $e) {
            return $this->sendInterval;
        }
    }
    
    /**
     * 检查是否达到每日发送上限
     */
    private function isDailyLimitReached($email, $clientIp) {
        try {
            $count = $this->DB->getColumn(
                "SELECT COUNT(*) FROM pre_email_verify 
                 WHERE (email = :email OR ip = :ip) 
                 AND DATE(created_at) = CURDATE()",
                [
                    ':email' => $email,
                    ':ip' => $clientIp
                ]
            );
            return $count >= $this->dailyLimit;
        } catch (\Exception $e) {
            return false;
        }
    }
    
    /**
     * 获取客户端IP
     */
    private function getClientIp() {
        $ip = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
        if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            $ips = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
            $ip = trim($ips[0]);
        }
        return $ip;
    }
    
    /**
     * 清理过期验证码
     * @param int $days 清理多少天前的过期记录
     * @return int 清理的记录数
     */
    public function cleanupExpiredCodes($days = 7) {
        try {
            $result = $this->DB->exec(
                "DELETE FROM pre_email_verify WHERE expire_at < DATE_SUB(NOW(), INTERVAL :days DAY)",
                [':days' => intval($days)]
            );
            return $result !== false ? $result : 0;
        } catch (\Exception $e) {
            return 0;
        }
    }
}
