// google_calendar.jsx — Google Calendar API 連携（読み取り専用）
// Google Identity Services (GIS) の Token Client を使用
// Ref: https://developers.google.com/identity/oauth2/web/guides/use-token-model

const GOOGLE_CLIENT_ID = '295436617621-8lh0ulqmo6m2o79v01hfi98pr4aotai7.apps.googleusercontent.com';
const GOOGLE_SCOPE = 'https://www.googleapis.com/auth/calendar.readonly';
const GOOGLE_TOKEN_KEY = 'echo.googleToken.v1';   // localStorage key
const GOOGLE_CALENDARS_KEY = 'echo.googleCalendars.v1'; // 選択中のカレンダーID

// ---- トークン管理 ----
function loadGoogleToken() {
  try {
    const raw = localStorage.getItem(GOOGLE_TOKEN_KEY);
    if (!raw) return null;
    const t = JSON.parse(raw);
    if (!t || !t.access_token) return null;
    if (t.expires_at && Date.now() > t.expires_at) return null;
    return t;
  } catch { return null; }
}
function saveGoogleToken(token) {
  try { localStorage.setItem(GOOGLE_TOKEN_KEY, JSON.stringify(token)); } catch {}
}
function clearGoogleToken() {
  try { localStorage.removeItem(GOOGLE_TOKEN_KEY); } catch {}
  try { localStorage.removeItem(GOOGLE_CALENDARS_KEY); } catch {}
}

// ---- 選択済みカレンダー設定 ----
function loadSelectedCalendars() {
  try {
    const raw = localStorage.getItem(GOOGLE_CALENDARS_KEY);
    if (!raw) return [];
    const arr = JSON.parse(raw);
    return Array.isArray(arr) ? arr : [];
  } catch { return []; }
}
function saveSelectedCalendars(list) {
  try { localStorage.setItem(GOOGLE_CALENDARS_KEY, JSON.stringify(list)); } catch {}
}

// ---- OAuth (GIS Token Client) ----
// GISが読み込まれるのを待つ
function waitForGIS(timeout = 10000) {
  return new Promise((resolve, reject) => {
    const start = Date.now();
    const check = () => {
      if (window.google && window.google.accounts && window.google.accounts.oauth2) {
        resolve();
      } else if (Date.now() - start > timeout) {
        reject(new Error('Google Identity Services の読み込みがタイムアウトしました'));
      } else {
        setTimeout(check, 100);
      }
    };
    check();
  });
}

// ログインフロー: ポップアップでGoogle認証 → アクセストークン取得
async function requestGoogleAuth() {
  await waitForGIS();
  return new Promise((resolve, reject) => {
    const tokenClient = window.google.accounts.oauth2.initTokenClient({
      client_id: GOOGLE_CLIENT_ID,
      scope: GOOGLE_SCOPE,
      prompt: 'consent',
      callback: (resp) => {
        if (resp.error) {
          reject(new Error(resp.error));
          return;
        }
        // resp = { access_token, expires_in, scope, token_type }
        const token = {
          access_token: resp.access_token,
          expires_at: Date.now() + (resp.expires_in || 3600) * 1000 - 60000, // 1分余裕
          scope: resp.scope,
        };
        saveGoogleToken(token);
        resolve(token);
      },
      error_callback: (err) => {
        reject(new Error(err.message || 'Google 認証に失敗しました'));
      },
    });
    tokenClient.requestAccessToken();
  });
}

// トークン取得（なければ新規認証）
async function getValidGoogleToken(interactive = false) {
  let token = loadGoogleToken();
  if (token) return token;
  if (!interactive) return null;
  return await requestGoogleAuth();
}

async function revokeGoogleToken() {
  const token = loadGoogleToken();
  if (token && token.access_token && window.google && window.google.accounts && window.google.accounts.oauth2) {
    try {
      window.google.accounts.oauth2.revoke(token.access_token, () => {});
    } catch {}
  }
  clearGoogleToken();
}

// ---- Calendar API ----
async function googleFetch(path, token) {
  const res = await fetch(`https://www.googleapis.com/calendar/v3${path}`, {
    headers: { Authorization: `Bearer ${token.access_token}` },
  });
  if (res.status === 401) {
    clearGoogleToken();
    throw new Error('Google トークンが無効になりました。再ログインしてください。');
  }
  if (!res.ok) {
    const body = await res.text();
    throw new Error(`Google API error (${res.status}): ${body.slice(0, 200)}`);
  }
  return res.json();
}

// カレンダーリスト取得
async function listGoogleCalendars() {
  const token = await getValidGoogleToken(false);
  if (!token) throw new Error('未ログイン');
  const data = await googleFetch('/users/me/calendarList?minAccessRole=reader', token);
  // data.items = [{ id, summary, backgroundColor, primary, accessRole, ... }]
  return (data.items || []).map(c => ({
    id: c.id,
    name: c.summary,
    color: c.backgroundColor || '#5B6CFF',
    primary: !!c.primary,
    accessRole: c.accessRole,
  }));
}

// イベント取得（指定カレンダー x 期間）
// デフォルトは -10年 〜 +10年 (全取得、最大 25,000件)
async function fetchGoogleEvents(calendarId, opts = {}) {
  const token = await getValidGoogleToken(false);
  if (!token) throw new Error('未ログイン');
  const now = new Date();
  const YEAR = 365 * 24 * 3600 * 1000;
  const timeMin = opts.timeMin || new Date(now.getTime() - 10 * YEAR).toISOString();
  const timeMax = opts.timeMax || new Date(now.getTime() + 10 * YEAR).toISOString();

  const all = [];
  let pageToken = null;
  let safety = 100; // 最大 100 ページ (25,000件)
  do {
    const params = new URLSearchParams({
      timeMin, timeMax,
      singleEvents: 'true',   // 定期予定を展開
      orderBy: 'startTime',
      maxResults: '250',
    });
    if (pageToken) params.set('pageToken', pageToken);
    const data = await googleFetch(
      `/calendars/${encodeURIComponent(calendarId)}/events?${params}`,
      token
    );
    if (data.items && data.items.length) all.push(...data.items);
    pageToken = data.nextPageToken || null;
    safety--;
    // 進捗表示 (option)
    if (opts.onProgress) opts.onProgress({ loaded: all.length, hasMore: !!pageToken });
  } while (pageToken && safety > 0);
  return all;
}

// Google イベント → Echo イベント形式
function normalizeGoogleEvent(gev, calMeta) {
  const startTs = gev.start.dateTime
    ? new Date(gev.start.dateTime).getTime()
    : new Date(gev.start.date + 'T00:00:00').getTime();
  const endTs = gev.end.dateTime
    ? new Date(gev.end.dateTime).getTime()
    : new Date(gev.end.date + 'T23:59:59').getTime();
  const allDay = !gev.start.dateTime;
  const title = gev.summary || '(無題)';

  // カテゴリ推定（タイトルから）
  const category = (function() {
    const t = title.toLowerCase();
    if (/class|lesson|授業|レッスン|英語|発音/.test(t)) return 'CLASS';
    if (/meeting|interview|1:1|standup|面接|ミーティング|打合せ|商談/.test(t)) return 'MEETING';
    if (/workout|gym|ジム|運動/.test(t)) return 'FITNESS';
    if (/flight|便|移動|travel/.test(t)) return 'TRAVEL';
    return 'CALENDAR';
  })();

  return {
    id: `ev:${calMeta.sourceId}:${gev.id}`,
    kind: 'event',
    ts: startTs,
    endTs: endTs,
    title,
    description: gev.description || '',
    location: gev.location || '',
    allDay,
    source: calMeta.sourceId,
    sourceName: calMeta.name,
    sourceColor: calMeta.color,
    calendar: calMeta.name,
    category,
    url: gev.htmlLink || null,    // ← Googleカレンダーの予定ページ
    rrule: null,
    recurring: !!gev.recurringEventId,
  };
}

// Google ソースIDを統一形式で生成
function googleSourceId(calendarId) {
  // メールアドレスっぽいIDを安全な形に
  const safe = calendarId.replace(/[^a-zA-Z0-9]/g, '-').slice(0, 40);
  return `gcal-${safe}`;
}

// 選択中のGoogleカレンダーを全部取り込んで DB に保存
// onProgress: ({calendar, loaded, hasMore}) => void  進捗通知
async function syncGoogleCalendars(onProgress) {
  const selected = loadSelectedCalendars();
  if (selected.length === 0) return { synced: 0, sources: 0 };
  let totalEvents = 0;
  for (const cal of selected) {
    const sourceId = googleSourceId(cal.id);
    const calMeta = { sourceId, name: cal.name, color: cal.color };
    const gevents = await fetchGoogleEvents(cal.id, {
      onProgress: (p) => onProgress && onProgress({ calendar: cal.name, ...p }),
    });
    const normalized = gevents
      .filter(g => g.status !== 'cancelled')
      .map(g => normalizeGoogleEvent(g, calMeta));

    // 既存のソースを更新 or 作成
    const sources = await DB.allSources();
    const existing = sources.find(s => s.id === sourceId);
    const source = {
      id: sourceId,
      name: cal.name,
      fileName: `google:${cal.id}`,
      color: cal.color,
      importedAt: Date.now(),
      eventCount: normalized.length,
      provider: 'google',
      googleCalendarId: cal.id,
      lastSyncAt: Date.now(),
      seed: false,
    };
    await DB.putSource(source);

    // そのソースの既存イベントを全削除してから挿入
    await DB.removeEventsBySource(sourceId);
    await DB.putEvents(normalized);
    totalEvents += normalized.length;
  }
  return { synced: totalEvents, sources: selected.length };
}

// 最後の同期時刻を取得（Googleソースの lastSyncAt のうち最新のもの）
async function getLastGoogleSyncAt() {
  try {
    const sources = await DB.allSources();
    const googleSources = sources.filter(s => s.provider === 'google');
    if (googleSources.length === 0) return null;
    return googleSources.reduce((max, s) => Math.max(max, s.lastSyncAt || 0), 0);
  } catch { return null; }
}

// 自動同期の条件: ログイン済み かつ 最後の同期から X 時間以上経過
async function shouldAutoSync(maxAgeMs = 2 * 3600 * 1000) {
  if (!loadGoogleToken()) return false;
  const selected = loadSelectedCalendars();
  if (selected.length === 0) return false;
  const last = await getLastGoogleSyncAt();
  if (!last) return true;
  return (Date.now() - last) > maxAgeMs;
}

Object.assign(window, {
  // OAuth
  requestGoogleAuth, revokeGoogleToken,
  loadGoogleToken, getValidGoogleToken,
  // Calendar list / selection
  listGoogleCalendars, loadSelectedCalendars, saveSelectedCalendars,
  // Sync
  syncGoogleCalendars, fetchGoogleEvents, normalizeGoogleEvent, googleSourceId,
  getLastGoogleSyncAt, shouldAutoSync,
  // Constants
  GOOGLE_CLIENT_ID, GOOGLE_SCOPE,
});
