import fsPublicDataManager from "../../../../../shared/fsPublicDataManager";
import { ToolIds, Img2ImgModelContextFx, ToolsContextType, ToolImg2ImgContextState, SsqApi, OutputType,  } from "./types";

declare const scroll_sequence_editor_data: any;

export async function actionGenerate(toolsState:ToolsContextType){
    console.log(' actionGenerate() called for toolsState:', toolsState);
    const { activeToolId, setActiveIo, tools, progress, progress: { updateProgress }, addOutput, setOutputActiveIndex, setOutputActiveSubIndex } = toolsState;
    const activeToolObject = toolsState.tools.find(tool => tool.id === activeToolId) ;

    //check that we have an active tool object
    if (!activeToolObject) {
        updateProgress({ 
            busy: false, 
            log: {
                level: 'error', 
                message: `actionGenerate() - no active tool found for tool id: ${activeToolId}`, 
                data: { activeToolObject: activeToolObject,   }
            }
        } );
        return;
    }

    const activeModelId = activeToolObject.currentModelId;
    const activeModelObject = activeToolObject.models.find(m => m.id === activeModelId);
    
    //check that we have an active model object
    if (!activeModelObject) {
        updateProgress({ 
            busy: false, 
            log: {
                level: 'error', 
                message: `actionGenerate() - no active model found for model id: ${activeModelId}`, 
                data: { activeModelObject: activeModelObject,   }
            }
        } );
        return;
    }

    // sync models def. 
    const isSyncModel = ['dalle-but-nothing-really-this-is-always-false'].includes(activeModelId); // add more sync models here

    // set "generating" state
    updateProgress({ 
        busy: 'generating', 
        log: { level: 'info', message: `Generation started "${activeToolId}/${activeModelId}" ${isSyncModel ? '(synchronous)' : ''}` } 
    });

    // START - IF CHANGING THE PAYLOAD, CHANGE IN THE PLUGIN AND BACKEND TOO
    type PayloadObj = {
        toolId: ToolIds; // already in request URL, 
        modelId: string; // model id, again, quite difficult to type this properly
        input:  any; // very difficult to type this properly - each model has its own input structure
    }
    // END - IF CHANGING THE PAYLOAD, CHANGE IN THE PLUGIN AND BACKEND TOO

    const payload: PayloadObj = {
        toolId: activeToolObject.id,
        modelId: activeModelObject.id,
        input: activeModelObject.modelState.input, 
    }

    

    try {
            const response = await fetch(`${scroll_sequence_editor_data.scrollSequenceApiUrl}/v2/media-tools/${isSyncModel ? 'runsync' : 'run'}`, { // run
                method: 'POST',
                headers: {
                    'Authorization': `${scroll_sequence_editor_data.fs_auth_hash}`,
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify(payload),
            });

            const data : SsqApi = await response.json();

            console.log(' data_____ ', data);

            // if data.fsPublicData exists, update the fsPublicDataManager
            if (data.fsPublicData) {
                console.log(' actionGenerate() - updating fsPublicDataManager with new data.fsPublicData:', data.fsPublicData);
                fsPublicDataManager.update(data.fsPublicData);
            }
            
            
            //if (!response.ok) { // handles non-2xx HTTP responses. To show API responses - i need to be watching for data.success === false  instead
            if (!data.success) { // act based on API response success field.
                updateProgress({ 
                    busy: false, 
                    log: { 
                        level: 'error', 
                        message: `Generation failed: ${data.error || response.statusText}`, 
                        data: { responseData: data, responseStatus: response.status }
                    } 
                });
                return;
            }



            // handle successful response
            console.log('Fetched data:SsqApiSuccess:', data);
            
            // Await polling and handle errors here
            const result = isSyncModel 
                ? data // synchronous models return final result immediately
                : await pollJobStatus(data.job_id!, (update) => {
                    // Update UI with progress/logs here
                    console.log('Polling update:', update);
                    if (update.logs && Array.isArray(update.logs)) {
                        updateProgress({
                            busy: 'generating',
                            log: { level: 'info', message: `Checking job: ${data.job_id} status: ${update.status}` }
                        });
                    }
                });

            console.log('Job completed! Final result:', result);

            if (result.output_urls && Array.isArray(result.output_urls)) {
                console.log(' actionGenerate() - output URLs:', result.output_urls);

                addOutput({
                    id: data.job_id!,
                    tool_id: activeToolObject.id,
                    model_id: activeModelObject.id,
                    input_object: activeModelObject.modelState.input,
                    output_urls: result.output_urls,
                    status: 'COMPLETED', // <-- Add this line!
                    _source: 'generation',
                })

                setActiveIo('output');
                setOutputActiveIndex(0);
                setOutputActiveSubIndex(0);

                // setOutputs( prev => {
                //     const newOutputs = result.output_urls!.map( (url:string) => {
                //         const output: OutputType = { 
                //             id: data.job_id!,
                //             tool_id: activeToolObject.id,
                //             model_id: activeModelObject.id,
                //             input_object: activeModelObject.modelState.input,
                //             //time_submitted: //Date.now(),
                //             output_urls: [url], // single URL in array

                //         };
                //         return output;
                //     });
                //     return [...prev, ...newOutputs];
                // } );


                updateProgress({ 
                    busy: false, 
                    log: { 
                        level: 'success', 
                        message: `Generation completed successfully. Output URLs received.`, 
                        data: { outputUrls: result.output_urls }
                    } 
                });
            } else {
                console.warn(' actionGenerate() - no output URLs found in result:', result);
                updateProgress({ 
                    busy: false, 
                    log: { 
                        level: 'warning', 
                        message: `Generation completed but no output URLs found.`, 
                        data: { result: result }
                    } 
                });
            }
            
    } catch (e: unknown){
        //console.error(' actionGenerate() - Generation error thrown:', e);
        updateProgress({ 
            busy: false, 
            log: { 
                level: 'error', 
                message: `Generation error thrown: ${e instanceof Error ? e.message : JSON.stringify(e)}`, // not really nice
                data: { error: e }
            } 
        });
        return;
    }

}
// helpers
async function pollJobStatus(jobId: string, onUpdate?: (data: any) => void): Promise<any> {
    const poll = async (resolve: (data: any) => void, reject: (err: any) => void) => {
        try {
            const res = await fetch(`${scroll_sequence_editor_data.scrollSequenceApiUrl}/v2/media-tools/check/${jobId}`, {
                method: 'GET',
                headers: {
                    'Authorization': `${scroll_sequence_editor_data.fs_auth_hash}`,
                    'Content-Type': 'application/json',
                },
            });
            const data = await res.json();
            if (onUpdate) onUpdate(data);

            if (['COMPLETED', 'SUCCESS'].includes(data.status)) {
                // Job completed successfully
                resolve(data);
            } else if ( ['starting', 'IN_QUEUE', 'IN_PROGRESS'].includes(data.status) ) {
                setTimeout(() => poll(resolve, reject), 2000); // poll every 2 seconds
            } else {
                // Unknown or error status
                console.error('pollJobStatus() Job status unknown or error:', data);
                reject(data);
            }
        } catch (err) {
            console.error('pollJobStatus() Error polling job status:', err);
            reject(err);
        }
    };

    return new Promise(poll);
}














/*
export async function actionGenerateModelFx(toolState:ToolsContextType){
    console.log(' actionGenerateModelFx() called');

    setTimeout( () => {
        console.log(' actionGenerateModelFx() generation simulated after timeout toolState:', toolState,  );
    }, 2000 );
}


export async function actionGenerateModelNb(toolState:ToolsContextType){
    console.log(' actionGenerateModelNb() called');
    // implement actual generation logic here
}

export async function actionGenerateModelHlo(toolState:ToolsContextType){
    console.log(' actionGenerateModelHlo() called');
    // implement actual generation logic here
}
export async function actionGenerateModelKdp(toolState:ToolsContextType){
    console.log(' actionGenerateModelKdp() called');
    // implement actual generation logic here
}

*/




/*

    

    // call one of the functions below based on the active model
    switch(activeModelObject.id){
        case 'fx':
            actionGenerateModelFx( toolsState );
            break;
        case 'nb':
            actionGenerateModelNb( toolsState );
            break;
        case 'hlo':
            actionGenerateModelHlo( toolsState );
            break;
        case 'kdp':
            actionGenerateModelKdp( toolsState );
            break;
        default:
            console.warn(' actionGenerate() - unknown model id:');
            // TODO:  set error in progress
            break;
    }


*/