import { VideoGenerationMode } from '../types/node';
import { 
    ImageGenerationResponseSchema, 
    VideoGenerationResponseSchema, 
    AudioGenerationResponseSchema,
    StoryboardResponseSchema,
    PromptOptimizationResponseSchema
} from '../types/schemas';
import { useModelStore } from '@lib/store/modelStore';
import { DefaultService, PromptOptimizationRequest } from '@lib/api';
import { ImageGenerationService, VideoGenerationService, AudioGenerationService, MusicGenerationService, LyricsGenerationService } from '@lib/services/generationService';
import { AnalysisService } from '@lib/services/analysisService';
import { ChatService } from '@lib/services/chatService';
import { urlToBase64 as utilsUrlToBase64, extractLastFrame as utilsExtractLastFrame } from '@/utils/mediaUtils';
import { logger } from '@/lib/utils/logger';

const log = logger.namespace('CanvasService');

// --- Helpers ---
// Re-export or delegate to utils to maintain backward compatibility if used elsewhere
export const urlToBase64 = utilsUrlToBase64;
export const extractLastFrame = utilsExtractLastFrame;

// --- API Wrappers ---

export const generateImage = async (
    prompt: string, 
    model: string, 
    inputImages: string[] = [], 
    options: { 
        aspectRatio?: string, 
        resolution?: string, 
        count?: number,
        negativePrompt?: string,
        styleId?: string,
        projectId?: string,
        onTaskId?: (taskId: string) => void
    } = {}
): Promise<string[]> => {
    log.log('Generating Image:', {
        prompt: prompt.substring(0, 100) + '...',
        model,
        inputImagesCount: inputImages.length,
        inputImages: inputImages.map(url => url.substring(0, 100) + '...'),
        options
    });

    try {
        const { taskId, result: resultPromise } = await ImageGenerationService.generate({
            prompt,
            model,
            imageInputs: inputImages.length > 0 ? inputImages : undefined,
            negativePrompt: options.negativePrompt,
            aspectRatio: options.aspectRatio,
            resolution: options.resolution,
            n: options.count,
            styleId: options.styleId,
            projectId: options.projectId
        });
        if (taskId && options.onTaskId) options.onTaskId(taskId);
        const result = await resultPromise;
        log.log('Image Generation Result:', result);

        if (result.status === 'success' && result.urls) {
            return ImageGenerationResponseSchema.parse(result.urls);
        }
        if (result.status === 'cancelled') {
            // 用户主动取消：上层会感知为「已取消」，这里不再视为错误日志
            throw new Error('已取消');
        }
        throw new Error(result.error || 'Generation failed without specific error');
    } catch (error: any) {
        if (error?.message === '已取消') {
            // 取消不打 error 日志，交给上层做静默处理
            throw error;
        }
        log.error('Image generation failed:', error);
        throw error;
    }
};

export const generateVideo = async (
    prompt: string, 
    model: string, 
    options: { 
        aspectRatio?: string, 
        count?: number, 
        generationMode?: VideoGenerationMode, 
        resolution?: string,
        cameraControl?: string,
        projectId?: string,
        negativePrompt?: string,
        shotType?: string,
        enableAudio?: boolean,
        duration?: number,
        onTaskId?: (taskId: string) => void
    } = {}, 
    inputImageBase64?: string | null,
    videoInput?: any,
    referenceImages?: string[],
    audioUrl?: string | null
): Promise<{ uri: string, isFallbackImage?: boolean, videoMetadata?: any, uris?: string[] }> => {
    try {
        const allImages: string[] = [];
        if (inputImageBase64) allImages.push(inputImageBase64);
        if (referenceImages) allImages.push(...referenceImages);
        const allVideos = videoInput ? (Array.isArray(videoInput) ? videoInput : [videoInput]) : undefined;
        const allAudio = audioUrl ? [audioUrl] : undefined;

        const { taskId, result: resultPromise } = await VideoGenerationService.generate({
            prompt,
            model,
            imageInputs: allImages.length > 0 ? allImages : undefined,
            videoInputs: allVideos,
            audioInputs: allAudio,
            aspectRatio: options.aspectRatio,
            resolution: options.resolution,
            n: options.count,
            duration: options.duration,
            cameraControl: options.cameraControl,
            projectId: options.projectId,
            negativePrompt: options.negativePrompt,
            shotType: options.shotType,
            enableAudio: options.enableAudio
        });
        if (taskId && options.onTaskId) options.onTaskId(taskId);
        const result = await resultPromise;

        if (result.status === 'success' && result.urls && result.urls.length > 0) {
            return VideoGenerationResponseSchema.parse({
                uri: result.urls[0],
                uris: result.urls
            });
        }
        if (result.status === 'cancelled') {
            // 用户主动取消：上层会感知为「已取消」，这里不再视为错误日志
            throw new Error('已取消');
        }
        throw new Error(result.error || 'Video generation failed');
    } catch (error: any) {
        if (error?.message === '已取消') {
            // 取消不打 error 日志，交给上层做静默处理
            throw error;
        }
        log.error('Video generation failed:', error);
        throw error;
    }
};

export interface AudioGenerationOptions {
    voice?: string;
    storyboardId?: string;
    projectId?: string;
    model?: string;
    referenceAudio?: string;
    persona?: any;
    emotion?: any;
    /** 创建任务后立即回调 taskId，与图片/视频/音乐统一，便于节点展示与刷新后恢复轮询 */
    onTaskId?: (taskId: string) => void;
}

export interface MusicGenerationOptions {
    model?: string;
    projectId?: string;
    prompt?: string;
    source?: string;
    sourceId?: string;
    /** 创建任务后立即回调 taskId，用于节点展示与画布刷新后恢复轮询 */
    onTaskId?: (taskId: string) => void;
}

export interface LyricsGenerationOptions {
    model?: string;
    mode?: 'write_full_song' | 'edit';
    seedLyrics?: string;
    title?: string;
    projectId?: string;
    source?: string;
    sourceId?: string;
    /** 创建任务后立即回调 taskId，与其它生成类型统一，便于节点展示与刷新后恢复轮询 */
    onTaskId?: (taskId: string) => void;
}

export const generateAudio = async (
    text: string,
    options: AudioGenerationOptions = {}
): Promise<string> => {
    log.log('Generating Audio:', { text, options });
    try {
        const {
            voice,
            model: providedModel,
            referenceAudio
        } = options;

        const model = providedModel || useModelStore.getState().getDefaultModelId('audio');

        const result = await AudioGenerationService.generate({
            text,
            voice,
            referenceAudio,
            model,
            projectId: options.projectId,
            onTaskId: options.onTaskId,
        });
        log.log('Audio Generation Result:', result);

        if (result.status === 'success' && result.urls && result.urls.length > 0) {
            return AudioGenerationResponseSchema.parse(result.urls[0]);
        }
        throw new Error(result.error || 'Audio generation failed');
    } catch (e) {
        log.error('Audio Generation Error:', e);
        throw e;
    }
};

export const generateMusic = async (
    lyrics: string,
    options: MusicGenerationOptions = {}
): Promise<string> => {
    log.log('Generating Music:', { lyrics: lyrics.substring(0, 100), options });
    try {
        const model = options.model || useModelStore.getState().getDefaultModelId('music');

        const result = await MusicGenerationService.generate({
            model,
            lyrics,
            prompt: options.prompt,
            projectId: options.projectId,
            source: options.source,
            sourceId: options.sourceId,
            onTaskId: options.onTaskId,
        });

        if (result.status === 'success' && result.urls && result.urls.length > 0) {
            return result.urls[0];
        }
        throw new Error(result.error || 'Music generation failed');
    } catch (e) {
        log.error('Music Generation Error:', e);
        throw e;
    }
};

export const generateLyrics = async (
    prompt: string,
    options: LyricsGenerationOptions = {}
): Promise<{ lyrics: string; songTitle?: string; styleTags?: string }> => {
    log.log('Generating Lyrics:', { prompt: prompt.substring(0, 100), options });
    const model = options.model || useModelStore.getState().getDefaultModelId('lyrics');
    return await LyricsGenerationService.generate({
        model,
        prompt,
        mode: options.mode || 'write_full_song',
        lyrics: options.seedLyrics,
        title: options.title,
        projectId: options.projectId,
        source: options.source,
        sourceId: options.sourceId,
        onTaskId: options.onTaskId,
    });
};

export const transcribeAudio = async (audioData: string): Promise<string> => {
    return await AudioGenerationService.transcribe(audioData);
};

export const connectLiveSession = async (
    onAudioData: (base64: string) => void,
    onClose: () => void
): Promise<any> => {
    return await ChatService.connectLiveSession(onAudioData, onClose);
};


// --- Stubs for Assistant/Analysis (until backend supports them) ---

export const sendChatMessage = async (
    history: { role: 'user' | 'model', parts: { text: string }[] }[], 
    newMessage: string,
    options?: { 
        isThinkingMode?: boolean, 
        isStoryboard?: boolean, 
        isHelpMeWrite?: boolean,
        onChunk?: (text: string) => void
    }
): Promise<string> => {
    return await ChatService.sendChatMessage(history, newMessage, options);
};

export const analyzeVideo = async (videoData: string, prompt: string, model?: string): Promise<string> => {
    return await AnalysisService.analyzeVideo(videoData, prompt, model);
};

export const editImageWithText = async (image: string, prompt: string, model?: string): Promise<string> => {
    // Could use generateImage with input image and prompt
    const defaultModel = useModelStore.getState().getDefaultModelId('image');
    if (!defaultModel && !model) {
        throw new Error("No image model selected or available.");
    }
    const res = await generateImage(prompt, model || defaultModel, [image]);
    return res[0];
};

export const planStoryboard = async (prompt: string, context?: string, projectId?: string): Promise<string[]> => {
     const res = await AnalysisService.planStoryboard(prompt, projectId);
     return StoryboardResponseSchema.parse(res);
};

export const orchestrateVideoPrompt = async (_images: string[], intent: string): Promise<string> => {
    return await VideoGenerationService.optimizePrompt(intent);
};

import { buildPromptWithTemplate } from '../utils/promptTemplates';

export const generateCharacterPrompt = async (
    prompt: string, 
    context?: string,
    options: { targetType?: 'image' | 'video', template?: string } = {}
): Promise<string> => {
    const targetType = options.targetType || 'image';
    const template = options.template || 'general';
    
    // Build prompt with template (frontend handles all template formatting)
    // For 'general' template, just use prompt as-is
    // For specific templates, apply formatting
    const formattedPrompt = template === 'general' 
        ? prompt 
        : buildPromptWithTemplate(prompt, template, targetType, context);
        
    const apiTargetType = targetType === 'video' 
        ? PromptOptimizationRequest.target_type.VIDEO 
        : PromptOptimizationRequest.target_type.IMAGE;

    const response = await DefaultService.optimizePromptEndpoint({
        prompt: formattedPrompt,
        target_type: apiTargetType,
        // template is no longer needed by backend, but keep for logging/debugging
        template: template
    });
    // BaseResponse structure: { code, message, data: { optimized_prompt: ... } }
    const res = (response as any).data?.data;

    return PromptOptimizationResponseSchema.parse(res?.optimized_prompt || formattedPrompt);
};
