<?php
declare(strict_types=1);

require_once __DIR__ . '/../helpers.php';
require_once __DIR__ . '/../security/_csrf.php';
require_once __DIR__ . '/../app/admin.php';
require_once __DIR__ . '/../auth/_auth.php';

// ---------- ログイン試行レート制限（DATA_DIR/login_rate.json） ----------
function tpcms_login_prefix(string $ip): array {
    if (str_starts_with($ip, '::ffff:')) $ip = substr($ip, 7);
    if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
        $p = explode('.', $ip);
        if (count($p) === 4) return ['v4:'.$p[0].'.'.$p[1].'.'.$p[2].'.0/24', 'v4'];
    }
    if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
        $bin = @inet_pton($ip);
        if ($bin !== false && strlen($bin) === 16) {
            $first64 = substr($bin, 0, 8);
            $parts = unpack('n4', $first64);
            $hex = array_map(fn($n)=>sprintf('%x', $n), $parts ?: []);
            return ['v6:'.implode(':', $hex).'/64', 'v6'];
        }
    }
    return ['raw:'.$ip, 'raw'];
}

/** 現在ブロック中かを判定（true=許可、false=ブロック中） */
function tpcms_login_rate_check_allow(string $ip): bool {
    [$prefix, $family] = tpcms_login_prefix($ip);
    $file = DATA_DIR . '/login_rate.json';
    $now  = time();
    $map = [];
    if (is_file($file)) {
        $j = @file_get_contents($file);
        if ($j !== false) { $a = json_decode($j, true); if (is_array($a)) $map = $a; }
    }
    $rec = isset($map[$prefix]) && is_array($map[$prefix]) ? $map[$prefix] : ['fail'=>[], 'blocked_until'=>0];
    return (int)($rec['blocked_until'] ?? 0) <= $now;
}

/** 失敗を記録（10分窓で5回超えたら15分ブロック） */
function tpcms_login_rate_record_fail(string $ip): void {
    [$prefix, $family] = tpcms_login_prefix($ip);
    $file = DATA_DIR . '/login_rate.json';
    $now  = time();
    $win  = $now - 600; // 10分

    $map = [];
    if (is_file($file)) {
        $j = @file_get_contents($file);
        if ($j !== false) { $a = json_decode($j, true); if (is_array($a)) $map = $a; }
    }
    $rec = isset($map[$prefix]) && is_array($map[$prefix]) ? $map[$prefix] : ['fail'=>[], 'blocked_until'=>0];

    $fails = array_values(array_filter(is_array($rec['fail'] ?? []) ? $rec['fail'] : [], fn($t)=> is_int($t) && $t >= $win));
    $fails[] = $now; // 今回の失敗を追加
    $rec['fail'] = $fails;

    if (count($fails) > 5) { // 10分で5回まで → 超えたらブロック
        $rec['blocked_until'] = $now + 15 * 60; // 15分
    }

    $map[$prefix] = $rec;
    if (!is_dir(DATA_DIR)) @mkdir(DATA_DIR, 0775, true);
    $json = json_encode($map, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
    if ($json !== false) {
        @file_put_contents($file, $json, LOCK_EX);
        @chmod($file, 0664);
    }
}

// ?return= をそのまま引き継ぐ（絶対URLやスキーム付きは破棄）
$rawRet = $_GET['return'] ?? '';
$rawRet = is_string($rawRet) ? $rawRet : '';
$allow  = ($rawRet !== '' && !preg_match('~^[a-z][a-z0-9+.\-]*://~i', $rawRet));
$return = $allow ? $rawRet : '';

$css = asset_url('/admin/assets/admin.css', true);
$js  = asset_url('/admin/assets/admin.js',  true);

$err = '';
$info = '';

// POST処理
if (($_SERVER['REQUEST_METHOD'] ?? '') === 'POST') {
  csrf_check_or_die();

  // POST側の return（成功時の復帰先）
  $postRet = $_POST['return'] ?? '';
  $postRet = is_string($postRet) ? $postRet : '';
  $okPostRet = ($postRet !== '' && !preg_match('~^[a-z][a-z0-9+.\-]*://~i', $postRet));
  $safeBase  = (defined('BASE_PATH') && BASE_PATH !== '/') ? BASE_PATH . '/' : '/';
  $okPostRet = $okPostRet && str_starts_with($postRet, $safeBase);
  $dest = $okPostRet ? $postRet : url_for('/admin/');

  $action = (string)($_POST['_action'] ?? '');

  // レート制限（ブロック中なら以降の処理をスキップ）
  $tpcms_blocked = false;
  $ip = (string)($_SERVER['REMOTE_ADDR'] ?? '');
  if ($ip !== '' && !tpcms_login_rate_check_allow($ip)) {
    $tpcms_blocked = true;
    $err = '一定回数のログインに失敗したため、一時的にブロックされています（15分後に再試行してください）。';
  }

  // 1) 初期管理者登録（未登録時のみ許可）
  if ($action === 'init' && !admin_exists()) {
    $email = strtolower(trim((string)($_POST['email'] ?? '')));
    $pass1 = (string)($_POST['pass'] ?? '');
    $pass2 = (string)($_POST['pass2'] ?? '');

    if ($email === '' || $pass1 === '' || $pass2 === '') {
      $err = 'メール・パスワードを入力してください。';
    } elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
      $err = 'メールアドレスの形式が正しくありません。';
    } elseif ($pass1 !== $pass2) {
      $err = 'パスワード（確認）が一致しません。';
    } elseif (strlen($pass1) < 8) {
      $err = 'パスワードは8文字以上にしてください。';
    } else {
      try {
              admin_create($email, $pass1, 'Admin');
              // 自動ログイン
              auth_login_success(['id' => 1, 'email' => $email, 'name' => 'Admin']);
              header('Location: ' . $dest, true, 302);
              exit;
            } catch (Throwable $e) {
        $err = '初期登録に失敗しました：' . $e->getMessage();
      }
    }
  }

  // 2) 通常ログイン（登録済み時）
  if ($action === 'login' && admin_exists() && !$tpcms_blocked) {
    $email = strtolower(trim((string)($_POST['email'] ?? '')));
    $pass  = (string)($_POST['pass'] ?? '');

    if ($email === '' || $pass === '') {
      $err = 'メール・パスワードを入力してください。';
    } elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
      $err = 'メールアドレスの形式が正しくありません。';
    } elseif (!admin_verify($email, $pass)) {
      $err = 'メールアドレスまたはパスワードが違います。';
      tpcms_login_rate_record_fail((string)($_SERVER['REMOTE_ADDR'] ?? ''));
    } else {
      $adm = admin_load() ?: ['email' => $email, 'name' => 'Admin'];
      auth_login_success(['id' => 1, 'email' => (string)$adm['email'], 'name' => (string)($adm['name'] ?? 'Admin')]);
      header('Location: ' . $dest, true, 302);
      exit;
    }
  }

  // 3) それ以外（状態不整合）
  if ($err === '' && !admin_exists() && $action !== 'init') {
    $err = '初期管理者が未登録です。先に登録してください。';
  } elseif ($err === '' && admin_exists() && $action !== 'login') {
    $err = '不正な操作です。';
  }
}

$hasAdmin = admin_exists();
?><!doctype html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>管理ログイン｜Template Party CMS</title>
  <link rel="stylesheet" href="<?= h($css) ?>">
</head>
<body class="login">

<div id="container">
  <h1><?= $hasAdmin ? '管理ログイン' : '初期管理者の登録' ?></h1>

  <?php if ($err !== ''): ?>
    <p class="err"><?= h($err) ?></p>
  <?php elseif ($info !== ''): ?>
    <p class="ok"><?= h($info) ?></p>
  <?php endif; ?>

  <?php if (!$hasAdmin): ?>
      <!-- 初期登録フォーム -->
      <form method="post" action="./login.php">
        <?= csrf_input_tag() ?>
        <?php if ($return !== ''): ?>
          <input type="hidden" name="return" value="<?= h($return) ?>">
        <?php endif; ?>
        <input type="hidden" name="_action" value="init">

        <p>
          <label>メールアドレス
            <input type="email" name="email" required autocomplete="username">
          </label>
        </p>
        <p>
          <label>パスワード
            <input type="password" name="pass" required autocomplete="new-password" minlength="8" placeholder="8文字以上">
          </label>
        </p>
        <p>
          <label>パスワード（確認）
            <input type="password" name="pass2" required autocomplete="new-password" minlength="8">
          </label>
        </p>
        <p><button type="submit" class="btn1">初期登録してログイン</button></p>
      </form>
  <?php else: ?>

    <!-- 通常ログインフォーム -->
    <form method="post" action="./login.php">
      <?= csrf_input_tag() ?>
      <?php if ($return !== ''): ?>
        <input type="hidden" name="return" value="<?= h($return) ?>">
      <?php endif; ?>
      <input type="hidden" name="_action" value="login">

      <p>
        <label>メールアドレス
          <input type="email" name="email" required autocomplete="username">
        </label>
      </p>
      <p>
        <label>パスワード
          <input type="password" name="pass" required autocomplete="current-password">
        </label>
      </p>
      <p><button type="submit" class="btn1">ログイン</button></p>
    </form>
  <?php endif; ?>
</div>

<script src="<?= h($js) ?>"></script>
</body>
</html>
