/**
 * Draft Service
 *
 * Service layer for Draft CRUD operations following the Logic Sandwich pattern.
 * This service handles all Draft database operations through Dexie.
 *
 * Architecture Compliance:
 * - This is a SERVICE layer - components should NOT import this directly
 * - Components should use ChatService which uses this service
 * - Services return plain objects, not Dexie observables
 *
 * Data Flow:
 * - UI -> Zustand Store -> ChatService -> DraftService -> Dexie
 */

import Dexie from 'dexie';
import { db, type DraftRecord } from './index';
import { SyncManager } from '../../services/sync-manager';

/**
 * Draft type used throughout the application (includes id)
 */
export interface Draft extends DraftRecord {
  id: number;
}

/**
 * Service class for Draft operations
 */
export class DraftService {
  /**
   * Save a draft to IndexedDB
   * @param draft - The draft to save (without id)
   * @returns The saved draft with generated id
   */
  static async saveDraft(draft: Omit<DraftRecord, 'id'>): Promise<Draft> {
    // 1. Always save to local DB first (Local-First)
    const id = await db.drafts.add(draft as DraftRecord);
    const savedDraft = { ...draft, id } as Draft;

    // 2. Check network status
    if (!SyncManager.isOnline()) {
      // Offline: Queue for future server sync
      await SyncManager.queueAction('saveDraft', { draftData: draft });
    }
    // Online: In future, we would sync immediately here: await api.saveDraft(...)

    return savedDraft;
  }

  /**
   * Get a draft by its ID
   * @param draftId - The ID of the draft
   * @returns The draft or null if not found
   */
  static async getDraftById(draftId: number): Promise<Draft | null> {
    const draft = await db.drafts.get(draftId);
    if (!draft) {
      return null;
    }
    // Return plain object, not Dexie observable
    return { ...draft } as Draft;
  }

  /**
   * Get the latest draft for a specific session
   * @param sessionId - The session ID to look up
   * @returns The latest draft or null if not found
   */
  static async getDraftBySessionId(sessionId: string): Promise<Draft | null> {
    // First get all drafts for this session
    const drafts = await db.drafts
      .where('sessionId')
      .equals(sessionId)
      .toArray();

    if (drafts.length === 0) {
      return null;
    }

    // Sort by createdAt descending to get the latest
    drafts.sort((a, b) => b.createdAt - a.createdAt);

    // Return the first (latest) draft
    return { ...drafts[0] } as Draft;
  }

  /**
   * Get all drafts ordered by creation date (newest first)
   * @returns Array of all drafts
   */
  static async getAllDrafts(): Promise<Draft[]> {
    const drafts = await db.drafts
      .orderBy('createdAt')
      .toArray();

    // Reverse to get newest first
    drafts.reverse();

    // Return plain objects, not Dexie observables
    return drafts.map(d => ({ ...d })) as Draft[];
  }

  /**
   * Get drafts by status
   * @param status - The status to filter by
   * @returns Array of drafts with the specified status
   */
  static async getDraftsByStatus(status: DraftRecord['status']): Promise<Draft[]> {
    const drafts = await db.drafts
      .where('status')
      .equals(status)
      .toArray();

    // Sort by createdAt descending
    drafts.sort((a, b) => b.createdAt - a.createdAt);

    return drafts.map(d => ({ ...d })) as Draft[];
  }

  /**
   * Update the status of a draft
   * @param draftId - The ID of the draft to update
   * @param status - The new status
   * @returns true if updated, false if not found
   */
  static async updateDraftStatus(
    draftId: number,
    status: DraftRecord['status']
  ): Promise<boolean> {
    const count = await db.drafts.update(draftId, { status });
    return count > 0;
  }

  /**
   * Update draft content
   * @param draftId - The ID of the draft to update
   * @param updates - The fields to update
   * @returns true if updated, false if not found
   */
  static async updateDraft(
    draftId: number,
    updates: Partial<Omit<DraftRecord, 'id'>>
  ): Promise<boolean> {
    const count = await db.drafts.update(draftId, updates);
    return count > 0;
  }

  /**
   * Delete a draft with cascade delete of associated chat logs
   * Story 3.2: Implements true privacy by removing all related data
   *
   * @param draftId - The ID of the draft to delete
   * @returns true if deleted, false if not found
   */
  static async deleteDraft(draftId: number): Promise<boolean> {
    // First check if draft exists
    const draft = await db.drafts.get(draftId);
    if (!draft) {
      return false;
    }

    // Use transaction for atomic cascade delete
    await db.transaction('rw', db.drafts, db.chatLogs, async () => {
      // Delete associated chat logs by sessionId
      await db.chatLogs
        .where('sessionId')
        .equals(draft.sessionId)
        .delete();

      // Delete the draft
      await db.drafts.delete(draftId);
    });

    // 3. Queue for sync if offline
    if (!SyncManager.isOnline()) {
      await SyncManager.queueAction('deleteDraft', { draftId });
    }

    return true;
  }

  /**
   * Delete all drafts for a session
   * @param sessionId - The session ID
   * @returns Number of drafts deleted
   */
  static async deleteSessionDrafts(sessionId: string): Promise<number> {
    return await db.drafts.where('sessionId').equals(sessionId).delete();
  }

  /**
   * Mark a draft as completed
   * Story 2.4: Adds completion timestamp and status
   *
   * @param draftId - The ID of the draft to mark as completed
   * @returns The updated draft, or null if not found
   */
  static async markAsCompleted(draftId: number): Promise<Draft | null> {
    const existing = await this.getDraftById(draftId);

    if (!existing) {
      return null;
    }

    // If already completed, just return it
    if (existing.status === 'completed') {
      return existing;
    }

    // Update status and add completion timestamp
    await db.drafts.update(draftId, {
      status: 'completed',
      completedAt: Date.now(),
    });

    // Queue for sync if offline
    if (!SyncManager.isOnline()) {
      await SyncManager.queueAction('completeDraft', { draftId });
    }

    // Return the updated draft
    return this.getDraftById(draftId);
  }

  /**
   * Get all completed drafts ordered by completion date (newest first)
   * Story 2.4: For history feed
   * Story 3.1: Enhanced with pagination support
   *
   * @param options - Pagination options
   * @returns Array of completed drafts
   */
  static async getCompletedDrafts(options?: {
    limit?: number;
    offset?: number;
  }): Promise<Draft[]> {
    const limit = options?.limit || 20;
    const offset = options?.offset || 0;

    // Use compound index or just createdAt for showing ALL history (drafts + completed)
    // Story 3.1: User wants to see "content generate" -> So we show everything
    const drafts = await db.drafts
      .orderBy('createdAt')
      .reverse() // Sort by createdAt descending
      .offset(offset)
      .limit(limit)
      .toArray();

    return drafts.map(d => ({ ...d })) as Draft[];
  }

  /**
   * Count total completed drafts
   * Story 3.1: For pagination hasMore detection
   *
   * @returns Count of completed drafts
   */
  static async getCompletedCount(): Promise<number> {
    return await db.drafts
      .where('status')
      .equals('completed')
      .count();
  }
}

if (typeof window !== 'undefined' && process.env.NODE_ENV !== 'production') {
  (window as any).DraftService = DraftService;
}
