import axios from 'axios';
import { db } from './db.js';
import { ensureValidAccessToken } from './spotify.js';

export async function syncUserData(uid: string): Promise<void> {
  const accessToken = await ensureValidAccessToken(uid);
  const headers = { Authorization: `Bearer ${accessToken}` };

  const [recentResp, topTracksShort, topTracksMed, topArtistsShort, topArtistsMed] = await Promise.all([
    axios.get('https://api.spotify.com/v1/me/player/recently-played?limit=20', { headers }),
    axios.get('https://api.spotify.com/v1/me/top/tracks?time_range=short_term&limit=20', { headers }),
    axios.get('https://api.spotify.com/v1/me/top/tracks?time_range=medium_term&limit=20', { headers }),
    axios.get('https://api.spotify.com/v1/me/top/artists?time_range=short_term&limit=20', { headers }),
    axios.get('https://api.spotify.com/v1/me/top/artists?time_range=medium_term&limit=20', { headers })
  ]);

  const trx = db.db.transaction(() => {
    const rpStmt = db.db.prepare('INSERT OR REPLACE INTO recently_played (id, user_id, played_at, track_json) VALUES (?, ?, ?, ?)');
    for (const item of recentResp.data.items) {
      rpStmt.run(item.played_at + ':' + item.track.id, uid, new Date(item.played_at).getTime(), JSON.stringify(item.track));
    }

    const ttDel = db.db.prepare('DELETE FROM top_tracks WHERE user_id=? AND time_range=?');
    const ttIns = db.db.prepare('INSERT INTO top_tracks (user_id, time_range, rank, track_json) VALUES (?, ?, ?, ?)');
    for (const [range, payload] of [
      ['short_term', topTracksShort.data],
      ['medium_term', topTracksMed.data],
    ] as const) {
      ttDel.run(uid, range);
      payload.items.forEach((t: any, idx: number) => ttIns.run(uid, range, idx + 1, JSON.stringify(t)));
    }

    const taDel = db.db.prepare('DELETE FROM top_artists WHERE user_id=? AND time_range=?');
    const taIns = db.db.prepare('INSERT INTO top_artists (user_id, time_range, rank, artist_json) VALUES (?, ?, ?, ?)');
    for (const [range, payload] of [
      ['short_term', topArtistsShort.data],
      ['medium_term', topArtistsMed.data],
    ] as const) {
      taDel.run(uid, range);
      payload.items.forEach((a: any, idx: number) => taIns.run(uid, range, idx + 1, JSON.stringify(a)));
    }
  });

  trx();
  db.db.prepare('UPDATE users SET last_synced_at=?, updated_at=? WHERE id=?').run(Date.now(), Date.now(), uid);
}

// Capture the user's current playback and persist as a recent play if changed
export async function captureNowPlaying(uid: string): Promise<void> {
  try {
    const accessToken = await ensureValidAccessToken(uid);
    const headers = { Authorization: `Bearer ${accessToken}` };
    const resp = await axios.get('https://api.spotify.com/v1/me/player/currently-playing?additional_types=track', {
      headers,
      validateStatus: () => true,
    });
    if (resp.status !== 200) return; // nothing to record
    const data = resp.data as any;
    if (!data?.is_playing || !data?.item) return;

    const track = data.item;
    const trackId: string | undefined = track?.id;
    if (!trackId) return;

    // Deduplicate: update existing row if same track found recently
    const recentRows = db.db.prepare('SELECT id, track_json, played_at FROM recently_played WHERE user_id=? ORDER BY played_at DESC LIMIT 50').all(uid) as Array<{ id: number; track_json: string; played_at: number }>;
    for (const row of recentRows) {
      try {
        const rowTrack = JSON.parse(row.track_json);
        if (rowTrack?.id === trackId) {
          // If the last record for this track is within 15 minutes, treat as the same session; update timestamp
          if (Date.now() - row.played_at < 15 * 60 * 1000) {
            db.db.prepare('UPDATE recently_played SET played_at = ?, track_json = ? WHERE id = ?').run(Date.now(), JSON.stringify(track), row.id);
            return;
          }
          break;
        }
      } catch {}
    }

    db.db
      .prepare('INSERT INTO recently_played (user_id, played_at, track_json) VALUES (?, ?, ?)')
      .run(uid, Date.now(), JSON.stringify(track));
  } catch {
    // ignore errors while capturing now playing to keep background loop robust
  }
}


