<?php
// app/controllers/auth.php

declare(strict_types=1);

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

final class AuthController extends BaseController {
  public static function register(Router $router, Container $container): void {
    $self = new self($container);
    $router->add('POST', '/api/auth/register', fn() => $self->registerUser());
    $router->add('POST', '/api/auth/login', fn() => $self->login());
    $router->add('POST', '/api/auth/2fa/verify', fn() => $self->verifyMfa());
    $router->add('POST', '/api/auth/refresh', fn() => $self->refresh());
    $router->add('POST', '/api/auth/logout', fn() => $self->logout());
    $router->add('POST', '/api/auth/password/forgot', fn() => $self->passwordForgot());
    $router->add('POST', '/api/auth/password/reset', fn() => $self->passwordReset());
    $router->add('POST', '/api/auth/2fa/setup', fn() => $self->setupMfa());
    $router->add('POST', '/api/auth/2fa/confirm', fn() => $self->confirmMfa());
    $router->add('POST', '/api/auth/2fa/disable', fn() => $self->disableMfa());
    $router->add('POST', '/api/auth/sse-key', fn() => $self->issueSseKey());
  }

  private function registerUser(): void {
    /** @var AuthService $auth */
    $auth = $this->auth();
    $body = read_json_body();
    $email = (string)($body['email'] ?? '');
    $password = (string)($body['password'] ?? '');
    $res = $auth->register($email, $password);
    if (empty($res['ok'])) {
      Response::json(['ok' => false, 'error' => ['code' => 'REGISTER_FAILED', 'message' => $res['error'] ?? 'failed']], 400);
      return;
    }
    Response::json(['ok' => true, 'data' => ['user_id' => $res['user_id'], 'role' => $res['role']]]);
  }

  private function login(): void {
    /** @var AuthService $auth */
    $auth = $this->auth();
    $body = read_json_body();
    $email = (string)($body['email'] ?? '');
    $password = (string)($body['password'] ?? '');
    $clientType = (string)($body['client_type'] ?? 'web');
    $deviceId = (string)($body['device_id'] ?? '');
    $res = $auth->login($email, $password, $clientType, $deviceId);
    if (empty($res['ok'])) {
      $err = ['code' => 'LOGIN_FAILED', 'message' => $res['error'] ?? 'failed'];
      $status = 401;
      if (!empty($res['retry_after'])) {
        $err['retry_after'] = (int)$res['retry_after'];
        $status = 429;
      }
      Response::json(['ok' => false, 'error' => $err], $status);
      return;
    }
    if (!empty($res['mfa_required'])) {
      Response::json(['ok' => true, 'data' => [
        'mfa_required' => true,
        'challenge_token' => $res['challenge_token'] ?? '',
      ]]);
      return;
    }
    $tokens = $res['tokens'] ?? [];
    if (!empty($tokens['access_token'])) {
      setcookie('scmedia_access_token', $tokens['access_token'], [
        'expires' => (int)($tokens['access_expires_at'] ?? 0),
        'path' => '/',
        'samesite' => 'Lax',
      ]);
      setcookie('access_token', '', [
        'expires' => time() - 3600,
        'path' => '/',
        'samesite' => 'Lax',
      ]);
    }
    Response::json(['ok' => true, 'data' => $tokens]);
  }

  private function verifyMfa(): void {
    /** @var AuthService $auth */
    $auth = $this->auth();
    $body = read_json_body();
    $challenge = (string)($body['challenge_token'] ?? '');
    $code = (string)($body['code'] ?? '');
    $clientType = (string)($body['client_type'] ?? 'web');
    $deviceId = (string)($body['device_id'] ?? '');
    $res = $auth->verifyMfa($challenge, $code, $clientType, $deviceId);
    if (empty($res['ok'])) {
      $err = ['code' => 'MFA_FAILED', 'message' => $res['error'] ?? 'failed'];
      $status = 401;
      if (!empty($res['retry_after'])) {
        $err['retry_after'] = (int)$res['retry_after'];
        $status = 429;
      }
      Response::json(['ok' => false, 'error' => $err], $status);
      return;
    }
    $tokens = $res['tokens'] ?? [];
    if (!empty($tokens['access_token'])) {
      setcookie('scmedia_access_token', $tokens['access_token'], [
        'expires' => (int)($tokens['access_expires_at'] ?? 0),
        'path' => '/',
        'samesite' => 'Lax',
      ]);
      setcookie('access_token', '', [
        'expires' => time() - 3600,
        'path' => '/',
        'samesite' => 'Lax',
      ]);
    }
    Response::json(['ok' => true, 'data' => $tokens]);
  }

  private function refresh(): void {
    /** @var AuthService $auth */
    $auth = $this->auth();
    $body = read_json_body();
    $refresh = (string)($body['refresh_token'] ?? '');
    $clientType = (string)($body['client_type'] ?? 'web');
    $deviceId = (string)($body['device_id'] ?? '');
    $res = $auth->refresh($refresh, $clientType, $deviceId);
    if (empty($res['ok'])) {
      Response::json(['ok' => false, 'error' => ['code' => 'REFRESH_FAILED', 'message' => $res['error'] ?? 'failed']], 401);
      return;
    }
    $tokens = $res['tokens'] ?? [];
    if (!empty($tokens['access_token'])) {
      setcookie('scmedia_access_token', $tokens['access_token'], [
        'expires' => (int)($tokens['access_expires_at'] ?? 0),
        'path' => '/',
        'samesite' => 'Lax',
      ]);
      setcookie('access_token', '', [
        'expires' => time() - 3600,
        'path' => '/',
        'samesite' => 'Lax',
      ]);
    }
    Response::json(['ok' => true, 'data' => $tokens]);
  }

  private function logout(): void {
    /** @var AuthService $auth */
    $auth = $this->auth();
    $body = read_json_body();
    $refresh = (string)($body['refresh_token'] ?? '');
    if ($refresh !== '') {
      $auth->logout($refresh);
    } else {
      $token = (string)($_COOKIE['scmedia_access_token'] ?? '');
      $auth->logoutByAccessToken($token);
    }
    setcookie('scmedia_access_token', '', [
      'expires' => time() - 3600,
      'path' => '/',
      'samesite' => 'Lax',
    ]);
    setcookie('access_token', '', [
      'expires' => time() - 3600,
      'path' => '/',
      'samesite' => 'Lax',
    ]);
    setcookie('scmedia_sse_key', '', [
      'expires' => time() - 3600,
      'path' => '/',
      'httponly' => true,
      'samesite' => 'Lax',
    ]);
    Response::json(['ok' => true]);
  }

  private function passwordForgot(): void {
    /** @var AuthService $auth */
    $auth = $this->auth();
    $body = read_json_body();
    $email = (string)($body['email'] ?? '');
    $res = $auth->passwordForgot($email);
    $data = $res;
    unset($data['ok']);
    Response::json(['ok' => true, 'data' => $data]);
  }

  private function passwordReset(): void {
    /** @var AuthService $auth */
    $auth = $this->auth();
    $body = read_json_body();
    $token = (string)($body['token'] ?? '');
    $password = (string)($body['password'] ?? '');
    $res = $auth->passwordReset($token, $password);
    if (empty($res['ok'])) {
      Response::json(['ok' => false, 'error' => ['code' => 'RESET_FAILED', 'message' => $res['error'] ?? 'failed']], 400);
      return;
    }
    Response::json(['ok' => true]);
  }

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

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

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

  private function issueSseKey(): void {
    /** @var AuthService $auth */
    $auth = $this->auth();
    $user = $auth->requireAuth();
    $key = $auth->issueSseKey((int)$user['id']);
    $ttl = (int)($key['expires_in'] ?? 60);
    setcookie('scmedia_sse_key', $key['key'], [
      'expires' => time() + max(10, $ttl),
      'path' => '/',
      'httponly' => true,
      'samesite' => 'Lax',
    ]);
    Response::json(['ok' => true, 'data' => $key]);
  }
}
