/**
 * 방어적 JSON 파싱 유틸리티
 *
 * PHP 백엔드가 JSON 출력 후 warning/error 텍스트를 붙여 보내는 경우 대응.
 * 예: {"success":true,"data":[...]}<br />Warning: Undefined variable...
 *
 * JSON.parse는 유효한 JSON 이후 trailing data가 있으면
 * "Unexpected non-whitespace character after JSON at position N" 에러를 발생시킴.
 * 이때 position N까지가 유효한 JSON이므로, 해당 지점까지 잘라서 재파싱.
 */

/**
 * PHP trailing output을 제거하고 JSON 파싱
 *
 * @param text - JSON 문자열 (trailing garbage 포함 가능)
 * @returns 파싱된 JSON 객체
 * @throws SyntaxError - 유효한 JSON이 아닌 경우 (복구 불가)
 */
export function safeJsonParse<T = unknown>(text: string): T {
  try {
    return JSON.parse(text);
  } catch (e) {
    if (!(e instanceof SyntaxError)) throw e;

    // "Unexpected ... after JSON at position N" 패턴에서 position 추출
    const posMatch = e.message.match(/position\s+(\d+)/i);
    if (posMatch) {
      const pos = parseInt(posMatch[1], 10);
      if (pos > 0) {
        try {
          const result = JSON.parse(text.substring(0, pos)) as T;
          console.warn(
            `[safeJsonParse] PHP trailing output detected (${text.length - pos} bytes). ` +
            `Trailing: ${text.substring(pos, pos + 200).replace(/\n/g, '\\n')}`
          );
          return result;
        } catch {
          // truncation으로도 실패하면 원래 에러 throw
        }
      }
    }

    throw e;
  }
}

/**
 * Response 객체에서 방어적으로 JSON 파싱
 *
 * response.json() 대신 response.text() + safeJsonParse() 사용.
 * PHP trailing output이 있어도 유효한 JSON을 복구.
 */
export async function safeResponseJson<T = unknown>(response: Response): Promise<T> {
  const text = await response.text();
  return safeJsonParse<T>(text);
}

/**
 * JSON 텍스트에서 trailing garbage 제거
 *
 * 프록시에서 사용: 파싱하지 않고 텍스트 레벨에서 trailing data만 제거.
 * JSON이 아니거나 trailing data가 없으면 원본 그대로 반환.
 */
export function stripJsonTrailingData(text: string): string {
  // JSON이 아닌 경우 원본 반환
  const trimmed = text.trimStart();
  if (!trimmed.startsWith('{') && !trimmed.startsWith('[')) {
    return text;
  }

  try {
    // 정상 파싱 되면 trailing data 없음
    JSON.parse(text);
    return text;
  } catch (e) {
    if (!(e instanceof SyntaxError)) return text;

    const posMatch = e.message.match(/position\s+(\d+)/i);
    if (posMatch) {
      const pos = parseInt(posMatch[1], 10);
      if (pos > 0) {
        const truncated = text.substring(0, pos);
        try {
          // truncated가 유효한 JSON인지 확인
          JSON.parse(truncated);
          console.warn(
            `[stripJsonTrailingData] Removed ${text.length - pos} bytes of trailing data`
          );
          return truncated;
        } catch {
          // 복구 불가 → 원본 반환
        }
      }
    }

    return text;
  }
}