<?php
function hv_token_create($uid,$type='access'){$e=($type==='access')?604800:2592000;$d=base64_encode(json_encode(['uid'=>$uid,'type'=>$type,'exp'=>time()+$e,'jti'=>bin2hex(random_bytes(8))]));return $d.'.'.hash_hmac('sha256',$d,TOKEN_SECRET);}
function hv_token_verify($token){$i=strrpos($token,'.');if($i===false)return null;$d=substr($token,0,$i);$s=substr($token,$i+1);if(!hash_equals(hash_hmac('sha256',$d,TOKEN_SECRET),$s))return null;$p=json_decode(base64_decode($d),true);if(!$p||$p['exp']<time())return null;return $p;}
function hv_get_user(){$h=isset($_SERVER['HTTP_AUTHORIZATION'])?$_SERVER['HTTP_AUTHORIZATION']:'';if(strpos($h,'Bearer ')!==0)return null;$p=hv_token_verify(substr($h,7));if(!$p||$p['type']!=='access')return null;$s=db()->prepare("SELECT id,email,display_name,avatar_url,provider,role,status FROM users WHERE id=:id AND status='active'");$s->execute(array(':id'=>$p['uid']));$u=$s->fetch();return $u?$u:null;}
function require_auth(){$u=hv_get_user();if(!$u)json_error('Unauthorized',401);return $u;}
function pw_table(){static $ok=false;if($ok)return;db()->exec("CREATE TABLE IF NOT EXISTS user_passwords(user_id INT UNSIGNED NOT NULL,password_hash VARCHAR(255) NOT NULL,PRIMARY KEY(user_id))ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");$ok=true;}

function _send_verify_email(string $email, string $name, string $token): void {
    $url  = 'https://tads.ctv.hanoi.vn/verify-email.html?token=' . $token;
    $body = "<html><body style='font-family:Arial,sans-serif;max-width:600px;margin:0 auto;'>
<div style='background:#8B3E18;padding:24px;border-radius:8px 8px 0 0;text-align:center;'>
  <h2 style='color:#fff;margin:0;'>🏛 Heritage Voice</h2>
  <p style='color:rgba(255,255,255,.8);margin:8px 0 0;font-size:14px;'>Xác nhận tài khoản của bạn</p>
</div>
<div style='background:#fff;border:1px solid #e0d8d0;border-top:none;padding:32px;border-radius:0 0 8px 8px;'>
  <p style='color:#2C1A0E;font-size:15px;'>Xin chào <strong>" . htmlspecialchars($name ?: $email) . "</strong>,</p>
  <p style='color:#666;line-height:1.7;'>Vui lòng bấm nút bên dưới để xác nhận email và kích hoạt tài khoản Heritage Voice.</p>
  <div style='text-align:center;margin:32px 0;'>
    <a href='" . $url . "' style='background:linear-gradient(135deg,#8B3E18,#C0622A);color:#fff;padding:14px 36px;border-radius:30px;text-decoration:none;font-size:15px;font-weight:700;display:inline-block;'>✅ Xác nhận email</a>
  </div>
  <p style='color:#aaa;font-size:12px;text-align:center;'>Link hiệu lực 24 giờ. Nếu bạn không đăng ký, hãy bỏ qua email này.</p>
</div></body></html>";
    try {
        if (file_exists('/home/tranhiep/.hv_secrets.php')) require_once '/home/tranhiep/.hv_secrets.php';
        $mp = '/home/tranhiep/tads.ctv.hanoi.vn/PHPMailer/src/';
        require_once $mp.'PHPMailer.php'; require_once $mp.'SMTP.php'; require_once $mp.'Exception.php';
        $mail = new PHPMailer\PHPMailer\PHPMailer(true);
        $mail->isSMTP(); $mail->Host='smtp.gmail.com'; $mail->SMTPAuth=true;
        $mail->Username='tranhiepstudio@gmail.com'; $mail->Password=MAIL_PASS;
        $mail->SMTPSecure='tls'; $mail->Port=587; $mail->CharSet='UTF-8'; $mail->Timeout=10;
        $mail->setFrom('tranhiepstudio@gmail.com','Heritage Voice');
        $mail->addAddress($email, $name?:$email);
        $mail->isHTML(true);
        $mail->Subject='[Heritage Voice] Xác nhận địa chỉ email';
        $mail->Body=$body;
        $mail->send();
    } catch (Exception $e) {}
}
function auth_verify_email(): void {
    $token=trim($_GET['token']??'');
    if(!$token) json_error('Token không hợp lệ',400);
    $s=db()->prepare("SELECT id,email_verify_expires FROM users WHERE email_verify_token=:t AND status='pending' LIMIT 1");
    $s->execute([':t'=>$token]);
    $u=$s->fetch();
    if(!$u) json_error('Token không hợp lệ hoặc đã dùng',400);
    if(new DateTime()>new DateTime($u['email_verify_expires'])) json_error('Token hết hạn. Vui lòng yêu cầu gửi lại email.',400);
    db()->prepare("UPDATE users SET status='active',email_verify_token=NULL,email_verify_expires=NULL WHERE id=:id")->execute([':id'=>$u['id']]);
    json_ok(['message'=>'Xác nhận thành công! Bạn có thể đăng nhập ngay.']);
}
function auth_resend_verify(): void {
    $b=body();$email=trim($b['email']??'');
    if(!$email) json_error('Vui lòng nhập email',400);
    $s=db()->prepare("SELECT id,display_name,status FROM users WHERE email=:e LIMIT 1");
    $s->execute([':e'=>$email]);$u=$s->fetch();
    if(!$u) json_error('Email không tồn tại',404);
    if($u['status']==='active') json_error('Tài khoản đã được xác nhận.',400);
    $token=bin2hex(random_bytes(32));
    db()->prepare("UPDATE users SET email_verify_token=:t,email_verify_expires=DATE_ADD(NOW(),INTERVAL 24 HOUR) WHERE id=:id")->execute([':t'=>$token,':id'=>$u['id']]);
    _send_verify_email($email,$u['display_name']??'',$token);
    json_ok(['message'=>'Đã gửi lại email xác nhận.']);
}
function auth_register(){rate_limit('register',3,300);$b=body();$email=trim($b['email']??'');$pass=$b['password']??'';$name=trim($b['display_name']??'');if(!filter_var($email,FILTER_VALIDATE_EMAIL))json_error('Email invalid');if(strlen($pass)<8)json_error('Mật khẩu tối thiểu 8 ký tự');
    if(!preg_match('/[0-9]/',$pass))json_error('Mật khẩu cần có ít nhất 1 chữ số');if(!$name)json_error('Name required');$c=db()->prepare("SELECT id FROM users WHERE email=:e");$c->execute([':e'=>$email]);if($c->fetch())json_error('Email exists',409);$hash=password_hash($pass,PASSWORD_BCRYPT);$phone=trim($b['phone']??'');$anon=bin2hex(random_bytes(16));$token=bin2hex(random_bytes(32));db()->prepare("INSERT INTO users(email,display_name,phone,provider,role,anonymous_id,status,email_verify_token,email_verify_expires,created_at,updated_at)VALUES(:e,:n,:ph,'email','member',:a,'pending',:tok,DATE_ADD(NOW(),INTERVAL 24 HOUR),NOW(),NOW())")->execute([':e'=>$email,':n'=>$name,':ph'=>$phone??null,':a'=>$anon,':tok'=>$token]);$uid=(int)db()->lastInsertId();_send_verify_email($email,$name,$token);pw_table();db()->prepare("INSERT INTO user_passwords(user_id,password_hash)VALUES(:u,:h)ON DUPLICATE KEY UPDATE password_hash=VALUES(password_hash)")->execute([':u'=>$uid,':h'=>$hash]);json_ok(['user'=>['id'=>$uid,'email'=>$email,'display_name'=>$name,'role'=>'member'],'access_token'=>hv_token_create($uid,'access'),'refresh_token'=>hv_token_create($uid,'refresh')],'OK');}
function auth_login(){rate_limit('login',5,60);$b=body();$email=trim($b['email']??'');$pass=$b['password']??'';if(!$email||!$pass)json_error('Missing fields');$s=db()->prepare("SELECT id,email,display_name,role,status FROM users WHERE email=:e AND provider='email'");$s->execute([':e'=>$email]);$u=$s->fetch();if(!$u)json_error('Invalid credentials',401);if($u['status']==='pending')json_error('Tài khoản chưa xác nhận email',403);if($u['status']==='banned')json_error('Tài khoản đã bị khóa',403);pw_table();$ps=db()->prepare("SELECT password_hash FROM user_passwords WHERE user_id=:u");$ps->execute([':u'=>$u['id']]);$pw=$ps->fetch();if(!$pw||!password_verify($pass,$pw['password_hash']))json_error('Invalid credentials',401);db()->prepare("UPDATE users SET last_seen_at=NOW() WHERE id=:id")->execute([':id'=>$u['id']]);
    audit_log('user_login', 'user', (string)$u['id'], 'Login via email');json_ok(['user'=>$u,'access_token'=>hv_token_create($u['id'],'access'),'refresh_token'=>hv_token_create($u['id'],'refresh'),'expires_in'=>604800],'OK');}
function auth_me(){
    $u = require_auth();
    $uid = $u['id'];

    // Đếm điểm đã nghe (complete_audio)
    $s1 = db()->prepare("SELECT COUNT(DISTINCT audio_point_id) FROM listen_events WHERE user_id=:u AND event_type='complete_audio'");
    $s1->execute([':u'=>$uid]);
    $listened = (int)$s1->fetchColumn();

    // Đếm điểm đến đã ghé (view_site)
    $s2 = db()->prepare("SELECT COUNT(DISTINCT site_id) FROM listen_events WHERE user_id=:u AND event_type='view_site'");
    $s2->execute([':u'=>$uid]);
    $visited = (int)$s2->fetchColumn();

    // Đếm QR đã quét (cả khi chưa đăng nhập dùng anonymous_id)
    $anon = $_SERVER['HTTP_X_ANONYMOUS_ID'] ?? null;
    $qr_where = "event_type='scan_qr' AND (user_id=:u1" . ($anon ? " OR anonymous_id=:anon" : "") . ")";
    $qr_params = [':u1' => $uid];
    if ($anon) $qr_params[':anon'] = $anon;
    $s3 = db()->prepare("SELECT COUNT(*) FROM listen_events WHERE $qr_where");
    $s3->execute($qr_params);
    $qr = (int)$s3->fetchColumn();

    // Đếm yêu thích
    $s4 = db()->prepare("SELECT COUNT(*) FROM user_favorites WHERE user_id=:u");
    $s4->execute([':u'=>$uid]);
    $favs = (int)$s4->fetchColumn();

    json_ok(['user'=>$u,'stats'=>[
        'listened_points' => $listened,
        'sites_visited'   => $visited,
        'qr_scanned'      => $qr,
        'favorites_count' => $favs,
    ]]);
}
function auth_refresh(){$b=body();$p=hv_token_verify($b['refresh_token']??'');if(!$p||$p['type']!=='refresh')json_error('Invalid token',401);json_ok(['access_token'=>hv_token_create($p['uid'],'access'),'expires_in'=>604800]);}
function auth_update_profile(){
    $u=require_auth();$b=body();$f=[];$p=[':id'=>$u['id']];
    if(!empty($b['display_name'])){$f[]='display_name=:n';$p[':n']=trim($b['display_name']);}
    if(!empty($b['avatar_url'])){$f[]='avatar_url=:av';$p[':av']=trim($b['avatar_url']);}
    if(!empty($b['current_password'])&&!empty($b['new_password'])){
        if(strlen($b['new_password'])<6)json_error('Mat khau moi qua ngan');
        pw_table();
        $ps=db()->prepare("SELECT password_hash FROM user_passwords WHERE user_id=:u");
        $ps->execute([':u'=>$u['id']]);$pw=$ps->fetch();
        if(!$pw||!password_verify($b['current_password'],$pw['password_hash']))json_error('Mat khau hien tai khong dung',401);
        $hash=password_hash($b['new_password'],PASSWORD_BCRYPT);
        db()->prepare("INSERT INTO user_passwords(user_id,password_hash)VALUES(:u,:h)ON DUPLICATE KEY UPDATE password_hash=VALUES(password_hash)")->execute([':u'=>$u['id'],':h'=>$hash]);
    }
    if($f){$f[]='updated_at=NOW()';db()->prepare("UPDATE users SET ".implode(',',$f)." WHERE id=:id")->execute($p);}
    json_ok(null,'OK');
}

function auth_logout() {
    $payload = get_token_payload();
    if ($payload && !empty($payload['jti'])) {
        // Thêm token vào blacklist
        db()->prepare("
            INSERT IGNORE INTO hv_token_blacklist (jti, user_id, expired_at)
            VALUES (:jti, :uid, :exp)
        ")->execute([
            ':jti' => $payload['jti'],
            ':uid' => $payload['uid'],
            ':exp' => date('Y-m-d H:i:s', $payload['exp']),
        ]);
        // Dọn dẹp token hết hạn định kỳ
        db()->exec("DELETE FROM hv_token_blacklist WHERE expired_at < NOW()");
    }
    json_ok(null, 'Đã đăng xuất');
}

function auth_request_reset(): void {
    if (!defined('MAIL_HOST')) require_once __DIR__ . '/mailer.php';
    rate_limit('reset_request', 3, 300);
    $b = body();
    $email = trim($b['email'] ?? '');
    if (!filter_var($email, FILTER_VALIDATE_EMAIL)) json_error('Email không hợp lệ');

    $s = db()->prepare("SELECT id, display_name FROM users WHERE email=:e AND provider='email' AND status='active'");
    $s->execute([':e' => $email]);
    $u = $s->fetch();

    // Luôn trả OK dù email không tồn tại (tránh enum)
    if (!$u) { json_ok(null, 'Nếu email tồn tại, bạn sẽ nhận được hướng dẫn.'); return; }

    $token = bin2hex(random_bytes(32));
    $exp   = date('Y-m-d H:i:s', time() + 3600); // 1 giờ

    db()->prepare("
        INSERT INTO password_reset_tokens (user_id, token, expires_at)
        VALUES (:u, :t, :e)
    ")->execute([':u' => $u['id'], ':t' => $token, ':e' => $exp]);

    // Gửi email
    $resetUrl = 'https://tads.ctv.hanoi.vn/reset-password.html?token=' . $token;
    $name     = $u['display_name'] ?: 'bạn';

    try {
        $mailerPath = '/home/tranhiep/tads.ctv.hanoi.vn/PHPMailer/src/';
        require_once $mailerPath . 'Exception.php';
        require_once $mailerPath . 'PHPMailer.php';
        require_once $mailerPath . 'SMTP.php';

        $mail = new PHPMailer\PHPMailer\PHPMailer(true);
        $mail->isSMTP();
        $mail->Host       = MAIL_HOST;
        $mail->SMTPAuth   = true;
        $mail->Username   = MAIL_USER;
        $mail->Password   = MAIL_PASS;
        $mail->SMTPSecure = 'tls';
        $mail->Port       = MAIL_PORT;
        $mail->CharSet    = 'UTF-8';
        $mail->setFrom(MAIL_FROM, MAIL_FROM_NAME);
        $mail->addAddress($email, $name);
        $mail->Subject = '[Heritage Voice] Đặt lại mật khẩu';
        $mail->isHTML(true);
        $mail->Body = "
<html><body style='font-family:Arial,sans-serif;max-width:600px;margin:0 auto;background:#f5f2ee;padding:20px;'>
  <div style='background:#8B3E18;padding:24px;border-radius:12px 12px 0 0;text-align:center;'>
    <h2 style='color:#fff;margin:0;'>🏛 Heritage Voice</h2>
  </div>
  <div style='background:#fff;border:1px solid #e0d8d0;border-top:none;padding:24px;border-radius:0 0 12px 12px;'>
    <h3 style='color:#2C1A0E;'>Xin chào {$name},</h3>
    <p style='color:#555;line-height:1.7;'>Chúng tôi nhận được yêu cầu đặt lại mật khẩu cho tài khoản của bạn.</p>
    <div style='text-align:center;margin:24px 0;'>
      <a href='{$resetUrl}' style='display:inline-block;background:#8B3E18;color:#fff;padding:14px 32px;border-radius:25px;text-decoration:none;font-weight:700;font-size:15px;'>
        Đặt lại mật khẩu →
      </a>
    </div>
    <p style='color:#888;font-size:12px;'>Link có hiệu lực trong <strong>1 giờ</strong>. Nếu bạn không yêu cầu, hãy bỏ qua email này.</p>
    <div style='margin-top:20px;padding-top:16px;border-top:1px solid #f0ece8;font-size:12px;color:#999;text-align:center;'>
      Heritage Voice · <a href='mailto:support@heritage-voice.vn' style='color:#8B3E18;'>support@heritage-voice.vn</a>
    </div>
  </div>
</body></html>";
        $mail->send();
    } catch (Throwable $e) {
        error_log('[HV reset mail] ' . $e->getMessage());
    }

    json_ok(null, 'Nếu email tồn tại, bạn sẽ nhận được hướng dẫn.');
}

function auth_do_reset(): void {
    rate_limit('reset_do', 5, 300);
    $b     = body();
    $token = trim($b['token'] ?? '');
    $pass  = $b['password'] ?? '';

    if (!$token) json_error('Thiếu token');
    if (strlen($pass) < 8) json_error('Mật khẩu tối thiểu 8 ký tự');
    if (!preg_match('/[0-9]/', $pass)) json_error('Mật khẩu cần có ít nhất 1 chữ số');

    $s = db()->prepare("
        SELECT * FROM password_reset_tokens
        WHERE token=:t AND used=0 AND expires_at > NOW()
    ");
    $s->execute([':t' => $token]);
    $row = $s->fetch();
    if (!$row) json_error('Link đặt lại mật khẩu không hợp lệ hoặc đã hết hạn', 400);

    $hash = password_hash($pass, PASSWORD_BCRYPT);
    pw_table();
    db()->prepare("
        INSERT INTO user_passwords (user_id, password_hash)
        VALUES (:u, :h)
        ON DUPLICATE KEY UPDATE password_hash=VALUES(password_hash)
    ")->execute([':u' => $row['user_id'], ':h' => $hash]);

    db()->prepare("UPDATE password_reset_tokens SET used=1 WHERE token=:t")
        ->execute([':t' => $token]);

    audit_log('password_reset', 'user', (string)$row['user_id'], 'Password reset via email token');
    json_ok(null, 'Đặt lại mật khẩu thành công');
}

function auth_upload_avatar(): void {
    $u = require_auth();
    if (empty($_FILES['avatar'])) json_error('No file', 400);
    $file = $_FILES['avatar'];
    if ($file['error'] !== UPLOAD_ERR_OK) json_error('Upload error: ' . $file['error'], 400);
    $allowed = ['image/jpeg' => 'jpg', 'image/png' => 'png', 'image/webp' => 'webp'];
    $mime = mime_content_type($file['tmp_name']);
    if (!isset($allowed[$mime])) json_error('Chỉ chấp nhận JPG/PNG/WEBP', 400);
    if ($file['size'] > 3 * 1024 * 1024) json_error('Ảnh tối đa 3MB', 400);
    $dir = __DIR__ . '/../images/avatars/';
    if (!is_dir($dir)) mkdir($dir, 0755, true);
    $filename = 'avatar_' . $u['id'] . '_' . time() . '.' . $allowed[$mime];
    if (!move_uploaded_file($file['tmp_name'], $dir . $filename)) json_error('Lưu file thất bại', 500);
    // Xoá avatar cũ nếu có
    $old = db()->prepare("SELECT avatar_url FROM users WHERE id=:id");
    $old->execute([':id' => $u['id']]);
    $row = $old->fetch();
    if ($row && $row['avatar_url'] && strpos($row['avatar_url'], '/images/avatars/') !== false) {
        $oldFile = $dir . basename(parse_url($row['avatar_url'], PHP_URL_PATH));
        if (file_exists($oldFile)) @unlink($oldFile);
    }
    $base = (isset($_SERVER['HTTPS']) ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST'];
    $url  = $base . '/images/avatars/' . $filename;
    db()->prepare("UPDATE users SET avatar_url=:url, updated_at=NOW() WHERE id=:id")
        ->execute([':url' => $url, ':id' => $u['id']]);
    json_ok(['url' => $url]);
}
