/**
 * User ID Manager
 * GTMウィジェット配置でのクロスオリジンiframe対応ユーザID管理
 * 
 * 優先順位:
 * 1. 親ウィンドウからpostMessageで受け取ったID
 * 2. localStorageに保存されたID（try/catchで安全にアクセス）
 * 3. 新規生成したID
 */

import { shortId } from '../utils/uuid.js';

const STORAGE_KEY = 'conversation-user-id';
const VISITOR_COOKIE = 'visitor_id';
const USER_ID_FORMAT = /^user_\d+(_[a-z0-9]+)?$/;

/**
 * 親ウィンドウへの postMessage 許可オリジンを取得する。
 * PHP (`includes/widget-frame.php`) が `window.__ALLOWED_ORIGINS__` に
 * home_url() のオリジン1件を注入する (§4.2)。未注入の場合は送信をスキップする
 * ための安全側フォールバックとして `null` を返す
 * (wp.org セキュリティ指摘回避 — `'*'` を targetOrigin に使わない)。
 * @returns {string|null}
 */
function getAllowedTargetOrigin() {
  try {
    const origins = typeof window !== 'undefined' ? window.__ALLOWED_ORIGINS__ : null;
    return Array.isArray(origins) && origins[0] ? origins[0] : null;
  } catch (e) {
    return null;
  }
}

/**
 * @type {string|null}
 */
let cachedUserId = null;

/**
 * @type {boolean}
 */
let isInitialized = false;

/**
 * 初期化前にIDが存在していたかどうか
 * @type {boolean}
 */
let hadValidIdAtInit = false;

/**
 * @type {Set<function(string): void>}
 */
const userIdChangeListeners = new Set();

/**
 * cookie から値を取得
 * @param {string} name
 * @returns {string|null}
 */
function getCookie(name) {
  try {
    const match = document.cookie.match(new RegExp('(?:^|; )' + name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + '=([^;]*)'));
    return match ? decodeURIComponent(match[1]) : null;
  } catch (e) {
    return null;
  }
}

/**
 * cookie に値を設定（1年間有効）
 * @param {string} name
 * @param {string} value
 */
function setCookie(name, value) {
  try {
    const maxAge = 365 * 24 * 60 * 60; // 1 year in seconds
    document.cookie = `${name}=${encodeURIComponent(value)}; path=/; max-age=${maxAge}; SameSite=None; Secure`;
  } catch (e) {
    console.warn('[UserIdManager] setCookie failed:', e.message);
  }
}

/**
 * 安全にlocalStorageから値を取得
 * @param {string} key
 * @returns {string|null}
 */
function safeGetItem(key) {
  try {
    return localStorage.getItem(key);
  } catch (e) {
    console.warn('[UserIdManager] localStorage.getItem failed:', e.message);
    return null;
  }
}

/**
 * 安全にlocalStorageに値を保存
 * @param {string} key 
 * @param {string} value 
 * @returns {boolean} 保存成功したかどうか
 */
function safeSetItem(key, value) {
  try {
    localStorage.setItem(key, value);
    return true;
  } catch (e) {
    console.warn('[UserIdManager] localStorage.setItem failed:', e.message);
    return false;
  }
}

/**
 * 新しいユーザIDを生成
 * @returns {string}
 */
function generateUserId() {
  return `user_${Date.now()}_${shortId()}`;
}

/**
 * ユーザIDの形式を検証
 * @param {string} userId 
 * @returns {boolean}
 */
function isValidUserId(userId) {
  if (!userId || typeof userId !== 'string') {
    return false;
  }
  // 空文字、"null"、"undefined"、空白のみは無効
  const trimmed = userId.trim();
  if (!trimmed || trimmed === 'null' || trimmed === 'undefined') {
    return false;
  }
  // user_で始まる形式を許可（厳密な形式チェックは緩和）
  return trimmed.startsWith('user_');
}

/**
 * ユーザIDを設定（内部用）
 * @param {string} userId 
 * @param {boolean} persist localStorageに保存するかどうか
 */
function setUserIdInternal(userId, persist = true) {
  if (!isValidUserId(userId)) {
    console.warn('[UserIdManager] Invalid userId rejected:', userId);
    return false;
  }
  
  const oldUserId = cachedUserId;
  cachedUserId = userId;
  
  if (persist) {
    setCookie(VISITOR_COOKIE, userId);
    safeSetItem(STORAGE_KEY, userId);
  }
  
  // 変更があった場合はリスナーに通知
  if (oldUserId !== userId) {
    userIdChangeListeners.forEach(listener => {
      try {
        listener(userId);
      } catch (e) {
        console.error('[UserIdManager] Listener error:', e);
      }
    });
  }
  
  return true;
}

/**
 * 親ウィンドウからのpostMessageを処理
 * @param {MessageEvent} event 
 */
function handleParentMessage(event) {
  // 親ウィンドウからのメッセージのみ処理
  if (event.source !== window.parent) {
    return;
  }
  
  const data = event.data;
  if (!data || typeof data !== 'object') {
    return;
  }
  
  // set-user-id メッセージを処理
  if (data.type === 'set-user-id' && data.userId) {
    console.log('[UserIdManager] Received userId from parent:', data.userId);
    if (setUserIdInternal(data.userId, true)) {
      // 親ウィンドウに確認を送信 (targetOrigin は window.__ALLOWED_ORIGINS__[0] に限定)
      const targetOrigin = getAllowedTargetOrigin();
      if (targetOrigin) {
        try {
          window.parent.postMessage({
            type: 'user-id-confirmed',
            userId: data.userId,
            timestamp: Date.now()
          }, targetOrigin);
        } catch (e) {
          console.warn('[UserIdManager] Failed to send confirmation:', e);
        }
      }
    }
  }
}

/**
 * UserIdManagerを初期化
 * @returns {string} 現在のユーザID
 */
function initialize() {
  if (isInitialized) {
    return cachedUserId;
  }
  
  // postMessageリスナーを登録
  window.addEventListener('message', handleParentMessage);

  // 優先順位: cookie > localStorage > 新規生成 (NS はサーバー側で ID を注入しない — D3/D4)
  const cookieId = getCookie(VISITOR_COOKIE);
  const storedId = safeGetItem(STORAGE_KEY);

  // 初期化前にIDが存在していたかどうかを記録（初回ユーザ判定用）
  hadValidIdAtInit = isValidUserId(cookieId) || isValidUserId(storedId);

  if (isValidUserId(cookieId)) {
    cachedUserId = cookieId;
    safeSetItem(STORAGE_KEY, cachedUserId);
    console.log('[UserIdManager] Loaded userId from cookie:', cachedUserId);
  } else if (isValidUserId(storedId)) {
    cachedUserId = storedId;
    // 既存localStorage IDをcookieにも昇格（マイグレーション）
    setCookie(VISITOR_COOKIE, cachedUserId);
    console.log('[UserIdManager] Migrated userId from localStorage to cookie:', cachedUserId);
  } else {
    // 新規生成
    cachedUserId = generateUserId();
    setCookie(VISITOR_COOKIE, cachedUserId);
    safeSetItem(STORAGE_KEY, cachedUserId);
    console.log('[UserIdManager] Generated new userId:', cachedUserId);
  }
  
  isInitialized = true;
  
  // 親ウィンドウにwidget-readyと共にユーザID情報を送信
  // (targetOrigin は window.__ALLOWED_ORIGINS__[0] に限定)
  const initTargetOrigin = getAllowedTargetOrigin();
  if (initTargetOrigin) {
    try {
      window.parent.postMessage({
        type: 'widget-user-id-request',
        currentUserId: cachedUserId,
        timestamp: Date.now()
      }, initTargetOrigin);
    } catch (e) {
      console.warn('[UserIdManager] Failed to request userId from parent:', e);
    }
  }
  
  return cachedUserId;
}

/**
 * 現在のユーザIDを取得
 * @returns {string}
 */
function getUserId() {
  if (!isInitialized) {
    initialize();
  }
  return cachedUserId;
}

/**
 * ユーザIDを外部から設定（親ウィンドウからの設定用）
 * @param {string} userId 
 * @returns {boolean}
 */
function setUserId(userId) {
  return setUserIdInternal(userId, true);
}

/**
 * ユーザID変更リスナーを追加
 * @param {function(string): void} listener 
 */
function addChangeListener(listener) {
  userIdChangeListeners.add(listener);
}

/**
 * ユーザID変更リスナーを削除
 * @param {function(string): void} listener 
 */
function removeChangeListener(listener) {
  userIdChangeListeners.delete(listener);
}

/**
 * ユーザIDが初回ユーザかどうかを判定
 * 初期化前にIDが存在していなかった場合にtrueを返す
 * @returns {boolean}
 */
function isFirstTimeUser() {
  // 初期化前の場合は、現在のストレージ状態をチェック
  if (!isInitialized) {
    const storedId = safeGetItem(STORAGE_KEY);
    return !isValidUserId(storedId);
  }
  // 初期化後は、初期化時点でIDが存在していたかどうかを返す
  return !hadValidIdAtInit;
}

/**
 * デバッグ情報を取得
 * @returns {Object}
 */
function getDebugInfo() {
  return {
    cachedUserId,
    isInitialized,
    hadValidIdAtInit,
    isFirstTimeUser: isFirstTimeUser(),
    storageAvailable: (() => {
      try {
        localStorage.setItem('__test__', '1');
        localStorage.removeItem('__test__');
        return true;
      } catch (e) {
        return false;
      }
    })(),
    storedUserId: safeGetItem(STORAGE_KEY),
    listenerCount: userIdChangeListeners.size
  };
}

// モジュールエクスポート
export const UserIdManager = {
  initialize,
  getUserId,
  setUserId,
  isFirstTimeUser,
  addChangeListener,
  removeChangeListener,
  getDebugInfo,
  // 内部関数もエクスポート（テスト用）
  _generateUserId: generateUserId,
  _isValidUserId: isValidUserId,
  _safeGetItem: safeGetItem,
  _safeSetItem: safeSetItem
};

// グローバルにも公開（レガシーコード対応）
if (typeof window !== 'undefined') {
  window.UserIdManager = UserIdManager;
}

export default UserIdManager;
