import { useState } from 'react';
//@ts-ignore
import { __ } from '@wordpress/i18n';
//@ts-ignore
import { TextControl, Button, Flex, FlexItem, ToggleControl, SelectControl, Spinner} from '@wordpress/components';
import { close } from '@wordpress/icons';
import { useVid2SsqContext, useToolsContext } from '../../../ContextProvider';

import InputMediaControl from '../../../to-be-shared/InputMediaControl';

import { VID2SSQ_MODEL_LOCAL } from '../../../constants'
import type { Vid2SsqModelContextLocal } from '../../../types';

declare const scroll_sequence_editor_data: any;

export default function ModelDisplayLocal() {
    const { activeIo, setActiveIo, addOutput, progress, progress: { busy, log, updateProgress }, setOutputActiveIndex, setOutputActiveSubIndex } = useToolsContext();
    const { models  } = useVid2SsqContext();

    const modelLocal = models.find(model => model.id === 'local')!;
    const modelState = modelLocal.modelState;
    const setModelState = modelLocal.setModelState;

    // Determine if we can generate
    const canGenerate = Boolean(modelState.input.video_url && modelState.input.prefix );

    const qualityOptionsMap = VID2SSQ_MODEL_LOCAL.config.qualityOptions.map( ( option ) => ( {
        label: `${option === 15 ? 'Aggressive (lossy)' : option === 5 ? 'Optimal (recommended)' : option === 2 ? 'Original (no compression)' : option}`,
        value: option,
    } ) );

    const downsizeOptionsMap = VID2SSQ_MODEL_LOCAL.config.downsizeOptions.map( ( option ) => ( {
        label: option === true ? 'Downsize to fit inside 1920x1920px rectangle (recommended)' : option === false ? 'No resize' : `${option}`,
        value: option,
    } ) );

    // FMPEG LOCAL IMPLEMENTATION
    const [ffmpeg, setFfmpeg] = useState<any>(null);


    // Main conversion logic (now loads ffmpeg if not loaded)
    const handleConvert = async () => {
        //setError(null);
        //setImages([]);
        //setLogs([]);
        //setProgress(0);        
        updateProgress({ 
            busy: 'generating', 
            log: { 
                level: 'info', 
                message: `Starting video to image sequence conversion...`, 
            } 
        });        


        let ffmpegInstance = ffmpeg;
        if (!ffmpegInstance) {
            //setLogs(l => [...l, 'Loading ffmpeg.wasm core...']);
            updateProgress({ 
                busy: 'generating', 
                log: { 
                    level: 'info', 
                    message: `Loading ffmpeg.wasm core...`, 
                } 
            });              
            const { FFmpeg } = await import('@ffmpeg/ffmpeg');
            const { fetchFile, toBlobURL } = await import('@ffmpeg/util');
            /*
             - I have added a copy of the ffmpeg-core* files to the cdn. 
             - There was an error with CORS, that I was able to fix by setting the headers in the R2 
             - Still getting "ReferenceError: SharedArrayBuffer is not defined"
             - https://github.com/ffmpegwasm/ffmpeg.wasm/issues/263
             => as a result, I am using the unpkg CDN for now.

            */
            const baseURL = 'https://unpkg.com/@ffmpeg/core@0.12.6/dist/umd';
            ffmpegInstance = new FFmpeg();
            ffmpegInstance.on('log', ({ message }: any) => {
                // optional really, but lets log for now. (there is a bunch of them)
                //setLogs(l => [...l, message])
                updateProgress({ 
                    busy: 'generating', 
                    log: { 
                        level: 'info', 
                        message: message, 
                    } 
                });                 
            });
            ffmpegInstance.on('progress', ({ progress }: any) => {
                //setProgress(Math.round(progress * 100)); // lets ignore that for now.
            });
            await ffmpegInstance.load({
                coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`, 'text/javascript'),
                wasmURL: await toBlobURL(`${baseURL}/ffmpeg-core.wasm`, 'application/wasm'),
            });
            setFfmpeg(ffmpegInstance);
            //setLogs(l => [...l, 'ffmpeg.wasm loaded.']);
            updateProgress({ 
                busy: 'generating', 
                log: { 
                    level: 'info', 
                    message: `ffmpeg.wasm loaded.`, 
                } 
            });              
        }

        if (!ffmpegInstance) {
            //setError('FFmpeg is not loaded.');
            updateProgress({ 
                busy: false, 
                log: { 
                    level: 'error', 
                    message: `Error: FFmpeg could not be loaded`, 
                } 
            });              
            return;
        }

        if (! modelState.input.video_url ) {
            //setError('Please select a video file.');
            updateProgress({ 
                busy: false, 
                log: { 
                    level: 'error', 
                    message: `Please select a video file.`, 
                } 
            });              
            return;
        }
        if (!modelState.input.prefix || !/^[a-z0-9]{1,16}$/.test(modelState.input.prefix)) {
            //setError('Prefix must be 1-16 characters, a-z and 0-9 only.');
            updateProgress({ 
                busy: false, 
                log: { 
                    level: 'error', 
                    message: `Prefix must be 1-16 characters, a-z and 0-9 only.`, 
                } 
            });              
            return;
        }

        // Load video file from URL
        let videoFile: File;
        try {
            const response = await fetch(modelState.input.video_url);
            const blob = await response.blob();
            videoFile = new File([blob], 'video.mp4', { type: 'video/mp4' });
        } catch (e: any) {
            //setError('Failed to load video file from URL.');
            updateProgress({
                busy: false,
                log: {
                    level: 'error',
                    message: `Failed to load video file from URL.`,
                }
            });
            return;
        }


        if (videoFile.size > 1000 * 1000 * 1000) {
            //setError('File seems too large. If you get in trouble, try a smaller file.');
            updateProgress({ 
                busy: false, 
                log: { 
                    level: 'error', 
                    message: `File seems too large. Please try a smaller file.`, 
                } 
            });              
        }

        //setIsConverting(true);
        //setLogs(l => [...l, 'Starting conversion...']);
        updateProgress({ 
            busy: 'generating', 
            log: { 
                level: 'info', 
                message: `Starting conversion...`, 
            } 
        });         

        try {
            // Write video file to ffmpeg FS
            await ffmpegInstance.writeFile('input.mp4', await (await import('@ffmpeg/util')).fetchFile(videoFile));
            // get codecs
            const codecs = await ffmpegInstance.exec('-codecs');
            console.log('Available codecs:', codecs);
            // Build ffmpeg args
            const qscale = `${modelState.input.quality}`;
            const scale = modelState.input.downsize
                ? "scale='min(1920,iw)':'min(1920,ih)':force_original_aspect_ratio=decrease"
                : "scale=iw:ih";
            // Output pattern
            //const outPattern = `${prefix}-%04d.jpg`; // JPG DOES NOT WORK
            const outPattern = `${modelState.input.prefix}-%04d.jpeg`; // Use JPG for better compatibility
            // Limit frames to 2000
            const args = [
                '-i', 'input.mp4',
                '-vf', scale,
                '-vframes', `${VID2SSQ_MODEL_LOCAL.config.maxFrames}`,
                '-qscale:v', qscale,
                outPattern,
            ];
            //setLogs(l => [...l, `Running ffmpeg: ffmpeg ${args.join(' ')}`]);
            updateProgress({ 
                busy: 'generating', 
                log: { 
                    level: 'info', 
                    message: `Running ffmpeg: ffmpeg ${args.join(' ')}`, 
                } 
            });                    
            await ffmpegInstance.exec(args);

            // List output files
            const files = await ffmpegInstance.listDir('/');
            console.log('FFmpeg FS files:', files);
            const fileNames = files.map((f: any) => typeof f === 'string' ? f : f.name);
            const imageFiles = fileNames.filter((f: string) => f.startsWith(modelState.input.prefix) && f.endsWith('.jpeg')).sort();
            if (imageFiles.length === 0) throw new Error('No images generated.');
            //setLogs(l => [...l, `Extracted ${imageFiles.length} images.`]);
            updateProgress({ 
                busy: 'generating', 
                log: { 
                    level: 'info', 
                    message: `Extracted ${imageFiles.length} images.`, 
                } 
            });  












            // Read images and create blob URLs
            // const imgs: string[] = [];
            // for (const fname of imageFiles) {
            //     const data = await ffmpegInstance.readFile(fname);
            //     const file = new File([data.buffer], fname, { type: 'image/jpeg' });
            //     imgs.push( URL.createObjectURL(file) );
            // }

            // NEW: create ssq-media post and upload images one-by-one to REST endpoint
            updateProgress({
                busy: 'uploading',
                log: { level: 'info', message: 'Creating scrollsequence post...' },
            });

            // 1) create ssq-media CPT
            let ssqPostId: number;
            try {
                const createResp = await fetch(`${scroll_sequence_editor_data.wpApiSettings?.root}wp/v2/ssq-media`, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'X-WP-Nonce': scroll_sequence_editor_data.wpApiSettings?.nonce || '',
                    },
                    body: JSON.stringify({
                        title: `Ssq Media: ${modelState.input.prefix}`,//'Scroll Sequence Media',
                        status: 'publish',
                    }),
                });
                if (!createResp.ok) {
                    const txt = await createResp.text();
                    throw new Error(`Failed to create ssq-media post: ${createResp.status} ${txt}`);
                }
                const created = await createResp.json();
                ssqPostId = created.id;
            } catch (err: any) {
                updateProgress({
                    busy: false,
                    log: { level: 'error', message: `Could not create ssq-media post: ${err.message || err}` },
                });
                throw err;
            }

            updateProgress({
                busy: 'uploading',
                log: { level: 'info', message: `Uploading ${imageFiles.length} images to ssq-media:${ssqPostId}...` },
            });


            // upload images sequentially to preserve index gaps
            const orderedUrls: string[] = [];
            for (let i = 0; i < imageFiles.length; i++) {
                const fname = imageFiles[i];
                try {
                    const data = await ffmpegInstance.readFile(fname);
                    const file = new File([data.buffer], fname);
                    // Create form data
                    const form = new FormData();
                    form.append('ssq_post_id', String(ssqPostId));
                    form.append('index', String(i));
                    form.append('slug', modelState.input.prefix);
                    form.append('image', file);

                    const uploadResp = await fetch(`${scroll_sequence_editor_data.wpApiSettings?.root}scroll-sequence/v2/upload-single`, {
                        method: 'POST',
                        body: form,
                        headers: {
                            'X-WP-Nonce': scroll_sequence_editor_data.wpApiSettings?.nonce || '',
                        },
                    });
                    if (!uploadResp.ok) {
                        const txt = await uploadResp.text();
                        throw new Error(`Upload failed for ${fname}: ${uploadResp.status} ${txt}`);
                    }
                    const uploadJson = await uploadResp.json();
                    const url = uploadJson.url;
                    orderedUrls[i] = url; // preserve order including gaps
                    // update progress per-file
                    updateProgress({
                        busy: 'uploading',
                        log: { level: 'info', message: `Uploaded ${fname} (index ${i})` },
                    });
                } catch (e: any) {
                    updateProgress({
                        busy: false,
                        log: { level: 'error', message: `Upload error for ${fname}: ${e.message || e}` },
                    });
                    throw e;
                }
            }

            console.log('Uploaded orderedUrls:', orderedUrls);

            // Add output (same as before), use ordered array (filter out nulls if you prefer)
            addOutput({
                id: `timestamp-${Date.now()}`,
                tool_id: 'vid2ssq',
                model_id: 'local',
                input_object: modelState.input,
                output_urls: orderedUrls,
                status: 'COMPLETED',
                _source: 'conversion',
            });
            setActiveIo('output');
            setOutputActiveIndex(0);
            setOutputActiveSubIndex(0);

            updateProgress({
                busy: false,
                log: { level: 'success', message: 'Conversion and upload complete.' },
            });




        } catch (e: any) {
            //setError(e.message || 'Conversion failed.');
            updateProgress({ 
                busy: false, 
                log: { 
                    level: 'error', 
                    message: e.message || 'Conversion failed.', 
                } 
            });              
        }

        //setIsConverting(false); // not sure, is this needed? 
    };

    return (
        <>
            <InputMediaControl
                label={'Video File'}
                progress={progress}

                //imageS3Url={modelState.input.video_url} // OLD 
                mediaType='video' // new 1/3
                mediaUrl={modelState.input.video_url} // new 2/3
                isLocalUrl={true} // new 3/3

                onUploadFinished={(mediaUrl: string, fileName: string) => {
                    console.log('ModelDisplayLocal handleUploadComplete() mediaUrls:', mediaUrl);
                    setModelState( ( prev : Vid2SsqModelContextLocal ) : Vid2SsqModelContextLocal => ( {
                        ...prev,
                        input: {
                            ...prev.input,
                            video_url: mediaUrl
                        }
                    }));
                }}
                onRemove={() => {
                    console.log('ModelDisplayLocal handleRemoveMedia() ');
                    setModelState( ( prev : Vid2SsqModelContextLocal ) : Vid2SsqModelContextLocal  => ( {
                        ...prev,
                        input: {
                            ...prev.input,
                            video_url: ''
                        }
                    }));
                }}
            />

            <TextControl 
                label="File Prefix"
                value={modelState.input.prefix}
                onChange={(newPrefix: string) => {
                    setModelState( ( prev : Vid2SsqModelContextLocal ) : Vid2SsqModelContextLocal  => ( {
                        ...prev,
                        input: {
                            ...prev.input,
                            prefix: newPrefix,
                        }
                    }));
                }}
            />

            <Flex gap={2} align="flex-end" style={{ marginBottom: '1rem' }}>
                <FlexItem style={{ flex: 1, minWidth: 100 }}>
                    <SelectControl
                        label={__("Quality Select", "scrollsequence")}
                        value={modelState.input.quality}
                        options={qualityOptionsMap}
                        onChange={(newQuality : typeof modelState.input.quality) => {
                            setModelState( ( prev : Vid2SsqModelContextLocal ) : Vid2SsqModelContextLocal => ( {
                                ...prev,
                                input: {
                                    ...prev.input,
                                    quality: newQuality
                                }
                            }));
                        }}
                        __next40pxDefaultSize
                        __nextHasNoMarginBottom
                    />
                </FlexItem>
                <FlexItem style={{ flex: 1, minWidth: 100 }}> 
                    <SelectControl
                        label={__("Downsize", "scrollsequence")}
                        value={modelState.input.downsize}
                        options={downsizeOptionsMap}
                        onChange={(newDownsize : typeof modelState.input.downsize) => {
                            setModelState( ( prev : Vid2SsqModelContextLocal ) : Vid2SsqModelContextLocal => ( {
                                ...prev,
                                input: {
                                    ...prev.input,
                                    downsize: newDownsize
                                }
                            }));
                        }}
                        __next40pxDefaultSize
                        __nextHasNoMarginBottom
                    />             
                </FlexItem>
            </Flex>

            <p>The local conversion does not cost any credits. Maximum frames 2000.</p>
            

            <div style={{ display: 'flex', justifyContent: 'flex-end', marginBottom: '1rem', marginTop: "4rem" }}>
                {busy && (
                    <Button
                        icon={close}
                        isDestructive
                        variant="secondary"
                        onClick={()=>{
                            updateProgress({ 
                                busy: false, 
                                log: { level: 'warning', message: 'Cancelled (video to image sequence ).' } 
                            });
                        }}
                        style={{ marginLeft: 12, marginRight: 12 }}
                    />
                )}
                <Button
                    variant={`${(activeIo === 'input') ? 'primary' : 'secondary'}`}
                    onClick={()=>{
                        handleConvert();
                    }}
                    disabled={ busy || !canGenerate }
                >
                    { busy 
                        ? 
                        <>
                            <Spinner style={{width: '16px', height: '16px',  marginTop:0, marginLeft:0}} />
                            { busy === 'generating' && 'Converting...'}
                            { busy === 'uploading' && 'Uploading...'}
                        </>
                        : 'Convert'
                    }
                </Button>         
            </div>

        </>
    );
}




