/**
 * Voice Agent KB Sync Service
 *
 * Orchestrates syncing Mawidi knowledge base documents to ElevenLabs.
 * Uses the optimized batch flow: create all text docs first, then link once.
 */

import { logger } from '@/lib/logger';
import {
  knowledgeBaseDocumentAdapter,
  knowledgeBaseFAQAdapter,
  voiceAgentKBSyncAdapter,
} from '@/lib/adapters/voice-agents';
import { elevenLabsKBService, type KBDocumentRef } from './elevenlabs-kb.service';

export class VoiceAgentKBSyncService {
  /**
   * Sync all processed KB documents for a user to ElevenLabs.
   * Optimized: creates all text docs individually, then links them all in one PATCH.
   */
  async syncAllDocuments(userId: string, agentId: string): Promise<{
    synced: number;
    failed: number;
    errors: string[];
  }> {
    let synced = 0;
    let failed = 0;
    const errors: string[] = [];
    const docsToLink: KBDocumentRef[] = [];

    try {
      // Get all completed KB documents for this user
      const documents = await (knowledgeBaseDocumentAdapter.findMany as (args: Record<string, unknown>) => Promise<unknown[]>)({
        where: {
          userId,
          status: 'COMPLETED',
        },
        include: {
          KnowledgeBaseChunk: {
            orderBy: { chunkIndex: 'asc' },
          },
        },
      });

      // Also get FAQs
      const faqs = await knowledgeBaseFAQAdapter.findMany({
        where: { userId, isActive: true },
      });

      // Step 1: Create text documents for each unsynced document
      for (const doc of documents as Array<Record<string, unknown>>) {
        try {
          // Check if already synced
          const existingSync = await voiceAgentKBSyncAdapter.findUnique({
            where: { userId_documentId: { userId, documentId: doc.id as string } },
          }) as Record<string, unknown> | null;

          if (existingSync?.syncStatus === 'synced' && existingSync.elevenlabsDocumentId) {
            synced++;
            // Include already-synced docs in the link call so they stay attached
            docsToLink.push({
              id: existingSync.elevenlabsDocumentId as string,
              name: (doc.title as string) || (doc.originalName as string),
            });
            continue;
          }

          // Build content from chunks
          const chunks = (doc.KnowledgeBaseChunk as Array<{ content: string }>) || [];
          const content = chunks.map((c) => c.content).join('\n\n');
          if (!content.trim()) continue;

          const docName = (doc.title as string) || (doc.originalName as string);
          const createResult = await elevenLabsKBService.createTextDocument(docName, content);

          if ('error' in createResult) {
            failed++;
            errors.push(`${doc.originalName as string}: ${createResult.error}`);
            await voiceAgentKBSyncAdapter.upsert({
              where: { userId_documentId: { userId, documentId: doc.id as string } },
              create: {
                userId,
                documentId: doc.id as string,
                syncStatus: 'failed',
                syncError: createResult.error,
              },
              update: {
                syncStatus: 'failed',
                syncError: createResult.error,
              },
            });
          } else {
            synced++;
            docsToLink.push({ id: createResult.id, name: docName });
            await voiceAgentKBSyncAdapter.upsert({
              where: { userId_documentId: { userId, documentId: doc.id as string } },
              create: {
                userId,
                documentId: doc.id as string,
                elevenlabsDocumentId: createResult.id,
                syncStatus: 'synced',
                lastSyncAt: new Date(),
              },
              update: {
                elevenlabsDocumentId: createResult.id,
                syncStatus: 'synced',
                lastSyncAt: new Date(),
                syncError: null,
              },
            });
          }
        } catch (error) {
          failed++;
          errors.push(`${doc.originalName as string}: ${error instanceof Error ? error.message : 'Unknown error'}`);
        }
      }

      // Create FAQ document if any
      const faqsArr = faqs as Array<Record<string, unknown>>;
      if (faqsArr.length > 0) {
        const faqContent = faqsArr
          .map(f => `Q: ${f.questionEn as string}\nA: ${f.answerEn as string}${f.questionAr ? `\n\nQ: ${f.questionAr as string}\nA: ${f.answerAr as string}` : ''}`)
          .join('\n\n---\n\n');

        const faqResult = await elevenLabsKBService.createTextDocument('FAQs', faqContent);
        if ('error' in faqResult) {
          errors.push(`FAQs: ${faqResult.error}`);
        } else {
          docsToLink.push({ id: faqResult.id, name: 'FAQs' });
        }
      }

      // Step 2: Link ALL documents to the agent in one PATCH call
      if (docsToLink.length > 0) {
        const linkResult = await elevenLabsKBService.linkDocumentsToAgent(agentId, docsToLink);
        if (!linkResult.success) {
          errors.push(`Link to agent failed: ${linkResult.error}`);
        }
      }

      logger.info('KB sync completed', { userId, synced, failed, linked: docsToLink.length });
    } catch (error) {
      logger.error('Error syncing KB documents', error, { userId });
      errors.push(`Sync error: ${error instanceof Error ? error.message : 'Unknown error'}`);
    }

    return { synced, failed, errors };
  }

  /**
   * Sync a single document to ElevenLabs
   */
  async syncDocument(userId: string, agentId: string, documentId: string): Promise<{
    success: boolean;
    error?: string;
  }> {
    try {
      const doc = await (knowledgeBaseDocumentAdapter.findFirst as (args: Record<string, unknown>) => Promise<unknown>)({
        where: { id: documentId, userId },
        include: {
          KnowledgeBaseChunk: { orderBy: { chunkIndex: 'asc' } },
        },
      });

      if (!doc) return { success: false, error: 'Document not found' };

      const docRecord = doc as Record<string, unknown>;
      const chunks = (docRecord.KnowledgeBaseChunk as Array<{ content: string }>) || [];
      const content = chunks.map((c) => c.content).join('\n\n');
      if (!content.trim()) return { success: false, error: 'Document has no content' };

      const result = await elevenLabsKBService.uploadDocument({
        agentId,
        name: (docRecord.title as string) || (docRecord.originalName as string),
        content,
      });

      if ('error' in result) {
        await voiceAgentKBSyncAdapter.upsert({
          where: { userId_documentId: { userId, documentId } },
          create: { userId, documentId, syncStatus: 'failed', syncError: result.error },
          update: { syncStatus: 'failed', syncError: result.error },
        });
        return { success: false, error: result.error };
      }

      await voiceAgentKBSyncAdapter.upsert({
        where: { userId_documentId: { userId, documentId } },
        create: {
          userId,
          documentId,
          elevenlabsDocumentId: result.documentId,
          syncStatus: 'synced',
          lastSyncAt: new Date(),
        },
        update: {
          elevenlabsDocumentId: result.documentId,
          syncStatus: 'synced',
          lastSyncAt: new Date(),
          syncError: null,
        },
      });

      return { success: true };
    } catch (error) {
      logger.error('Error syncing document', error, { documentId });
      return { success: false, error: 'Failed to sync document' };
    }
  }

  /**
   * Remove a document from ElevenLabs sync
   */
  async unsyncDocument(userId: string, agentId: string, documentId: string): Promise<{
    success: boolean;
    error?: string;
  }> {
    try {
      const sync = await voiceAgentKBSyncAdapter.findUnique({
        where: { userId_documentId: { userId, documentId } },
      }) as Record<string, unknown> | null;

      if (!sync) return { success: true };

      if (sync.elevenlabsDocumentId) {
        await elevenLabsKBService.deleteDocument(agentId, sync.elevenlabsDocumentId as string);
      }

      // adapter update requires { where: { id: string } }
      await voiceAgentKBSyncAdapter.update({
        where: { id: sync.id as string },
        data: { syncStatus: 'deleted', elevenlabsDocumentId: null },
      });

      return { success: true };
    } catch (error) {
      logger.error('Error unsyncing document', error, { documentId });
      return { success: false, error: 'Failed to unsync document' };
    }
  }

  /**
   * Get sync status for all user documents
   */
  async getSyncStatus(userId: string): Promise<Array<{
    documentId: string;
    documentName: string;
    syncStatus: string;
    lastSyncAt: Date | null;
    syncError: string | null;
  }>> {
    const documents = await knowledgeBaseDocumentAdapter.findMany({
      where: { userId, status: 'COMPLETED' },
      select: { id: true, originalName: true, title: true },
    });

    const syncs = await voiceAgentKBSyncAdapter.findMany({
      where: { userId },
    });

    const syncMap = new Map(
      (syncs as Array<Record<string, unknown>>).map(s => [s.documentId as string, s])
    );

    return (documents as Array<Record<string, unknown>>).map(doc => {
      const sync = syncMap.get(doc.id as string);
      return {
        documentId: doc.id as string,
        documentName: (doc.title as string) || (doc.originalName as string),
        syncStatus: (sync?.syncStatus as string) || 'not_synced',
        lastSyncAt: (sync?.lastSyncAt as Date) || null,
        syncError: (sync?.syncError as string) || null,
      };
    });
  }
}

export const voiceAgentKBSyncService = new VoiceAgentKBSyncService();
