<?php
// app/controllers/account.php

declare(strict_types=1);

use ScMedia\Http\Response;
use ScMedia\Http\Router;
use ScMedia\Services\AuthService;

final class AccountController extends BaseController {
  public static function register(Router $router, Container $container): void {
    $self = new self($container);
    $router->add('GET', '/account', fn() => $self->page());
    $router->add('GET', '/api/account', fn() => $self->getAccount());
    $router->add('POST', '/api/account', fn() => $self->updateAccount());
    $router->add('POST', '/api/account/email', fn() => $self->updateEmail());
    $router->add('POST', '/api/account/password', fn() => $self->updatePassword());
    $router->add('POST', '/api/account/avatar', fn() => $self->uploadAvatar());
    $router->add('GET', '/api/account/avatar', fn() => $self->getAvatar());
  }

  private function page(): void {
    $i18n = $this->loadI18n(['common', 'account']);
    $this->renderView(__DIR__ . '/../views/pages/account.php', $i18n);
  }

  private function getAccount(): void {
    /** @var AuthService $auth */
    $auth = $this->auth();
    $user = $auth->requireAuth();
    $profile = self::getProfile($this->services(), (int)$user['id']);
    Response::json(['ok' => true, 'data' => $profile]);
  }

  private function updateAccount(): void {
    /** @var AuthService $auth */
    $auth = $this->auth();
    $user = $auth->requireAuth();
    $body = read_json_body();
    $nickname = isset($body['nickname']) ? trim((string)$body['nickname']) : null;
    $ui = is_array($body['ui'] ?? null) ? $body['ui'] : null;
    self::updateProfile($this->services(), (int)$user['id'], $nickname, $ui);
    Response::json(['ok' => true]);
  }

  private function updateEmail(): void {
    /** @var AuthService $auth */
    $auth = $this->auth();
    $user = $auth->requireAuth();
    $body = read_json_body();
    $email = (string)($body['email'] ?? '');
    $res = $auth->changeEmail((int)$user['id'], $email);
    if (empty($res['ok'])) {
      Response::json(['ok' => false, 'error' => ['code' => 'EMAIL_FAILED', 'message' => $res['error'] ?? 'failed']], 400);
      return;
    }
    Response::json(['ok' => true]);
  }

  private function updatePassword(): void {
    /** @var AuthService $auth */
    $auth = $this->auth();
    $user = $auth->requireAuth();
    $body = read_json_body();
    $current = (string)($body['current'] ?? '');
    $next = (string)($body['next'] ?? '');
    $res = $auth->changePassword((int)$user['id'], $current, $next);
    if (empty($res['ok'])) {
      Response::json(['ok' => false, 'error' => ['code' => 'PASSWORD_FAILED', 'message' => $res['error'] ?? 'failed']], 400);
      return;
    }
    Response::json(['ok' => true]);
  }

  private function uploadAvatar(): void {
    /** @var AuthService $auth */
    $auth = $this->auth();
    $user = $auth->requireAuth();
    if (!isset($_FILES['avatar'])) {
      Response::json(['ok' => false, 'error' => ['code' => 'FILE_REQUIRED', 'message' => 'avatar required']], 400);
      return;
    }
    $file = $_FILES['avatar'];
    if (!is_array($file) || ($file['error'] ?? UPLOAD_ERR_NO_FILE) !== UPLOAD_ERR_OK) {
      Response::json(['ok' => false, 'error' => ['code' => 'UPLOAD_FAILED', 'message' => 'upload failed']], 400);
      return;
    }
    $size = (int)($file['size'] ?? 0);
    if ($size <= 0 || $size > 5 * 1024 * 1024) {
      Response::json(['ok' => false, 'error' => ['code' => 'FILE_TOO_LARGE', 'message' => 'max 5MB']], 400);
      return;
    }
    $tmp = (string)($file['tmp_name'] ?? '');
    $mime = (string)($file['type'] ?? '');
    $data = $tmp !== '' ? file_get_contents($tmp) : false;
    if ($data === false) {
      Response::json(['ok' => false, 'error' => ['code' => 'READ_FAILED', 'message' => 'read failed']], 400);
      return;
    }
    self::updateAvatar($this->services(), (int)$user['id'], $mime, $data);
    Response::json(['ok' => true]);
  }

  private function getAvatar(): void {
    /** @var AuthService $auth */
    $auth = $this->auth();
    $user = $auth->requireAuth();
    $row = self::getAvatarRow($this->services(), (int)$user['id']);
    if (!$row || empty($row['avatar_blob'])) {
      http_response_code(404);
      return;
    }
    $mime = (string)($row['avatar_mime'] ?? 'image/png');
    header('Content-Type: ' . $mime);
    echo $row['avatar_blob'];
  }

  private function loadI18n(array $packages = ['common']): array {
    $settings = $this->settings();
    $all = $settings->getAll();
    $lang = (string)($all['general']['language'] ?? 'en');
    $cookieLang = isset($_COOKIE['scmedia_lang']) ? (string)$_COOKIE['scmedia_lang'] : '';
    if (preg_match('/^[a-z]{2}$/', $cookieLang)) {
      $lang = $cookieLang;
    }

    $dict = $this->readI18nDict($lang);
    if ($lang !== 'en' && count($dict) === 0) {
      $lang = 'en';
      $dict = $this->readI18nDict($lang);
    }

    $dict = $this->filterI18nPackages($dict, $packages);
    $t = function(string $key, string $fallback = '') use ($dict): string {
      $val = $dict[$key] ?? '';
      return $val !== '' ? $val : ($fallback !== '' ? $fallback : $key);
    };

    return [
      'lang' => $lang,
      'dict' => $dict,
      't' => $t,
      'debugToolsEnabled' => (bool)($this->config()['app']['debug_tools_enabled'] ?? false),
    ];
  }

  private function renderView(string $path, array $vars = []): void {
    if (!is_file($path)) {
      Response::json(['ok' => false, 'error' => 'View not found'], 404);
      return;
    }
    extract($vars, EXTR_SKIP);
    ob_start();
    require $path;
    $html = ob_get_clean();
    Response::html($html);
  }

  private function readI18nDict(string $lang): array {
    $path = __DIR__ . '/../../public/assets/i18n/' . basename($lang) . '.json';
    if (!is_file($path)) return [];
    $raw = file_get_contents($path);
    if ($raw === false) return [];
    $data = json_decode($raw, true);
    return is_array($data) ? $data : [];
  }

  private function i18nPackages(): array {
    return [
      'common' => [
        'prefixes' => ['common', 'nav', 'queue', 'job'],
        'keys' => ['auth.logout', 'actions.theme', 'settings.language'],
      ],
      'account' => [
        'prefixes' => ['account', 'theme', 'settings.ui'],
        'keys' => ['settings.language'],
      ],
    ];
  }

  private function filterI18nPackages(array $dict, array $packages): array {
    $map = $this->i18nPackages();
    $out = [];
    $wanted = [];
    foreach ($packages as $p) {
      if (isset($map[$p])) {
        $wanted[] = $map[$p];
      }
    }
    foreach ($wanted as $pkg) {
      foreach (($pkg['prefixes'] ?? []) as $prefix) {
        foreach ($dict as $k => $v) {
          if (str_starts_with($k, $prefix . '.')) {
            $out[$k] = $v;
          }
        }
      }
      foreach (($pkg['keys'] ?? []) as $key) {
        if (array_key_exists($key, $dict)) {
          $out[$key] = $dict[$key];
        }
      }
    }
    return $out;
  }

  private static function getProfile(array $services, int $userId): array {
    $db = $services['db'];
    self::ensureProfile($db, $userId);
    $user = $db->fetchOne("SELECT email FROM users WHERE id = :id", [':id' => $userId]) ?? [];
    $row = $db->fetchOne("SELECT nickname, ui_prefs_json, avatar_blob FROM user_profiles WHERE user_id = :id", [':id' => $userId]) ?? [];
    $ui = json_decode((string)($row['ui_prefs_json'] ?? '{}'), true);
    return [
      'profile' => [
        'email' => (string)($user['email'] ?? ''),
        'nickname' => (string)($row['nickname'] ?? ''),
        'avatar_present' => !empty($row['avatar_blob']),
      ],
      'ui' => is_array($ui) ? $ui : [],
    ];
  }

  private static function updateProfile(array $services, int $userId, ?string $nickname, ?array $ui): void {
    $db = $services['db'];
    self::ensureProfile($db, $userId);
    if ($nickname !== null) {
      $db->exec("UPDATE user_profiles SET nickname = :n, updated_at = NOW() WHERE user_id = :id", [
        ':n' => $nickname,
        ':id' => $userId,
      ]);
    }
    if ($ui !== null) {
      $row = $db->fetchOne("SELECT ui_prefs_json FROM user_profiles WHERE user_id = :id", [':id' => $userId]) ?? [];
      $current = json_decode((string)($row['ui_prefs_json'] ?? '{}'), true);
      $current = is_array($current) ? $current : [];
      $merged = array_replace_recursive($current, $ui);
      $db->exec("UPDATE user_profiles SET ui_prefs_json = :j, updated_at = NOW() WHERE user_id = :id", [
        ':j' => json_encode($merged, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
        ':id' => $userId,
      ]);
    }
  }

  private static function updateAvatar(array $services, int $userId, string $mime, string $data): void {
    $db = $services['db'];
    self::ensureProfile($db, $userId);
    $db->exec("UPDATE user_profiles SET avatar_blob = :b, avatar_mime = :m, updated_at = NOW() WHERE user_id = :id", [
      ':b' => $data,
      ':m' => $mime,
      ':id' => $userId,
    ]);
  }

  private static function getAvatarRow(array $services, int $userId): ?array {
    $db = $services['db'];
    self::ensureProfile($db, $userId);
    return $db->fetchOne("SELECT avatar_blob, avatar_mime FROM user_profiles WHERE user_id = :id", [':id' => $userId]);
  }

  private static function ensureProfile($db, int $userId): void {
    $db->exec("INSERT IGNORE INTO user_profiles (user_id, created_at, updated_at) VALUES (:id, NOW(), NOW())", [
      ':id' => $userId,
    ]);
  }
}
