import { CookieOptions, Request } from 'express';

export const AUTH_COOKIE_NAME = '_aT';

/**
 * _aT 인증쿠키 공통 옵션.
 *  - signin/refresh(set)·signout(clear)이 **동일 옵션**을 써야 옛 쿠키가 정상적으로 덮어써지고
 *    삭제된다. 옵션 불일치 시 옛 쿠키가 안 치워져 누적되고, 만료된 옛 _aT 가 먼저 읽혀 메인 API 401 → 튕김.
 *  - 앱은 www ↔ api 크로스사이트라 https 환경에선 sameSite='none' + secure 가 필수다.
 *    (sameSite=Lax(기본)면 cross-site XHR 에 쿠키가 안 실려 로그인 직후 메인 API 가 401 난다.)
 *  - 로컬(http) 개발은 secure 쿠키가 불가하므로 lax 로 폴백한다.
 *    ※ prod 의 NODE_ENV 가 'dev' 라 NODE_ENV 로 분기하면 안 되고, 요청의 https 여부로 판단한다.
 */
export function authCookieOptions(req: Request, withMaxAge = false): CookieOptions {
  const proto =
    ((req.headers['x-forwarded-proto'] as string) ?? req.protocol ?? '') + '';
  const isHttps = proto.includes('https') || req.secure === true;

  const opts: CookieOptions = {
    httpOnly: true,
    path: '/',
    secure: isHttps,
    sameSite: isHttps ? 'none' : 'lax',
  };
  if (withMaxAge) opts.maxAge = 1000 * 60 * 60 * 12; //* 12시간
  return opts;
}

/**
 * 인증 토큰 후보 목록 추출 (raw Cookie 헤더의 모든 _aT + Authorization Bearer).
 *  - 과거 로그인의 옛 _aT(만료, 다른 path/속성)가 안 지워진 채 새 _aT와 공존하면
 *    `Cookie: _aT=옛만료; _aT=새것` 처럼 _aT가 여러 개 전송된다. 이때 cookie-parser는
 *    **첫 번째(옛 만료)** 만 req.cookies에 담아, 서버가 만료 토큰을 읽고 401 → 로그인 직후 튕김.
 *    (prod 로그 실측: signin 직후 cookie=[mem옛/만료, mem새/유효] 인데 401 다발)
 *  - 그래서 단일 토큰이 아니라 **후보 전부**를 돌려주고, 가드가 verify 성공하는 토큰을 고른다.
 *  - Authorization 헤더(프론트 저장 토큰)도 후보에 포함해 쿠키 미전송 기기까지 커버한다.
 */
export function getAuthTokenCandidates(req: Request): string[] {
  const out: string[] = [];

  const rawCookie = req.headers.cookie;
  if (rawCookie) {
    for (const part of rawCookie.split(';')) {
      const idx = part.indexOf('=');
      if (idx < 0) continue;
      const k = part.slice(0, idx).trim();
      const v = part.slice(idx + 1).trim();
      if (k === AUTH_COOKIE_NAME && v) out.push(v);
    }
  }

  const auth = req.headers['authorization'];
  if (typeof auth === 'string' && auth.startsWith('Bearer ')) {
    const t = auth.slice(7).trim();
    if (t && !out.includes(t)) out.push(t);
  }

  return out;
}
