/**
 * Sync service for keeping local SQLite cache in sync with Convex.
 * Provides offline-first functionality with background sync.
 */

import { ConvexReactClient } from "convex/react";
import { api } from "../../convex/_generated/api";
import {
  initDatabase,
  getLastSyncTimestamp,
  setLastSyncTimestamp,
  getCachedHashes,
  getCachedCardCount,
  upsertCards,
  clearCache,
} from "./localDatabase";
import type { CardHashEntry } from "../recognition";

export interface SyncStatus {
  isInitialized: boolean;
  isSyncing: boolean;
  lastSync: number;
  localCardCount: number;
  error?: string;
}

export interface SyncService {
  initialize: () => Promise<void>;
  sync: () => Promise<void>;
  getHashes: () => Promise<CardHashEntry[]>;
  getStatus: () => SyncStatus;
  clearLocalCache: () => Promise<void>;
  onStatusChange: (callback: (status: SyncStatus) => void) => () => void;
}

/**
 * Create a sync service instance.
 */
export function createSyncService(convexClient: ConvexReactClient): SyncService {
  let status: SyncStatus = {
    isInitialized: false,
    isSyncing: false,
    lastSync: 0,
    localCardCount: 0,
  };
  
  const listeners = new Set<(status: SyncStatus) => void>();
  
  function notifyListeners() {
    listeners.forEach((cb) => cb(status));
  }
  
  function updateStatus(partial: Partial<SyncStatus>) {
    status = { ...status, ...partial };
    notifyListeners();
  }
  
  return {
    /**
     * Initialize the local database and load cached data.
     */
    async initialize() {
      try {
        await initDatabase();
        
        const [lastSync, cardCount] = await Promise.all([
          getLastSyncTimestamp(),
          getCachedCardCount(),
        ]);
        
        updateStatus({
          isInitialized: true,
          lastSync,
          localCardCount: cardCount,
          error: undefined,
        });
        
        console.log(`[SyncService] Initialized with ${cardCount} cached cards`);
      } catch (error) {
        console.error("[SyncService] Initialization failed:", error);
        updateStatus({
          error: error instanceof Error ? error.message : "Initialization failed",
        });
      }
    },
    
    /**
     * Sync with Convex - fetch new/updated cards.
     */
    async sync() {
      if (status.isSyncing) {
        console.log("[SyncService] Sync already in progress");
        return;
      }
      
      updateStatus({ isSyncing: true, error: undefined });
      
      try {
        // Get cards updated since last sync
        const lastSync = status.lastSync;
        
        // Query Convex for updated cards
        // Note: This uses the HTTP client for one-off queries
        const cards = lastSync > 0
          ? await convexClient.query(api.cards.listUpdatedAfter, { since: lastSync })
          : await convexClient.query(api.cards.list, {});
        
        if (cards && cards.length > 0) {
          // Convert to local format and save
          const localCards = cards.map((card) => ({
            scryfallId: card.scryfallId,
            oracleId: card.oracleId,
            name: card.name,
            setCode: card.setCode,
            collectorNumber: card.collectorNumber,
            rarity: card.rarity,
            artist: card.artist,
            imageUri: card.imageUri,
            hash: new Uint8Array(card.hash),
            hashVersion: card.hashVersion,
            updatedAt: card.updatedAt,
          }));
          
          await upsertCards(localCards);
          console.log(`[SyncService] Synced ${localCards.length} cards`);
        }
        
        // Update sync timestamp
        const now = Date.now();
        await setLastSyncTimestamp(now);
        
        // Update status
        const cardCount = await getCachedCardCount();
        updateStatus({
          isSyncing: false,
          lastSync: now,
          localCardCount: cardCount,
        });
        
        console.log(`[SyncService] Sync complete. ${cardCount} cards cached.`);
      } catch (error) {
        console.error("[SyncService] Sync failed:", error);
        updateStatus({
          isSyncing: false,
          error: error instanceof Error ? error.message : "Sync failed",
        });
      }
    },
    
    /**
     * Get cached hashes for recognition.
     */
    async getHashes() {
      return getCachedHashes();
    },
    
    /**
     * Get current sync status.
     */
    getStatus() {
      return status;
    },
    
    /**
     * Clear local cache and re-sync.
     */
    async clearLocalCache() {
      await clearCache();
      updateStatus({
        lastSync: 0,
        localCardCount: 0,
      });
    },
    
    /**
     * Subscribe to status changes.
     */
    onStatusChange(callback: (status: SyncStatus) => void) {
      listeners.add(callback);
      return () => listeners.delete(callback);
    },
  };
}
