import {
    ToolbarGroup, ToolbarButton, Dropdown, Button, TextareaControl, ToggleControl, Notice, Spinner,
    __experimentalToggleGroupControl as ToggleGroupControl,
    __experimentalToggleGroupControlOption as ToggleGroupControlOption,
    //@ts-ignore
} from '@wordpress/components';
//@ts-ignore: Cannot find module '@wordpress/element' or its corresponding type declarations.
import { useState, useRef } from '@wordpress/element';
//@ts-ignore: Cannot find module '@wordpress/i18n' or its corresponding type declarations.
import { __ } from '@wordpress/i18n';
//@ts-ignore
import { useSelect, useDispatch } from '@wordpress/data';
// @ts-ignore
import { parse, getBlockTypes, createBlock   } from '@wordpress/blocks';
import NoticeTracking from '../../../shared/NoticeTracking';

declare const scroll_sequence_editor_data :any

/**

This is a reuasable component that will be part of the block controls for the scene, container and core/group blocks, 
It will be used to toggle the chat feature on and off for these blocks.

Context: 
1) container block
2) scene-sticky block
3) scene-fixed block
4) HOC group blocks that 

Actions:
1) generate, edit and delete the inner blocks 
2) generate the CSS for the inner blocks
3) generate the animation for the inner blocks

Originally I was thinking of having a "accept/reject" button after the AI prediction, but I believe that using native undo/redo functionality is better.

 */

export type OnSubmitPromptProps = {
        action: 'generate' | 'style' | 'animate',
        prompt: string,
        loading: boolean,
        setLoading: any,
        error: string | null,
        setError: any    
}

const DEFAULT_GENERATE_PROMPT = `
Generate a hero section with a "Hello World" heading, "Another Day on Earth" subheading, and a call-to-action button that says "Go".
`.trim();

const DEFAULT_ANIMATE_PROMPT = `
Add a on scroll fade-in animation to the heading and subheading between 0% and 20%. Add a scale from 0 to 1 animation to the call-to-action button between 60% and 80%.
`.trim();

export default function ChatButton({clientId}: {clientId: string}) {
    const [ action, setAction ] = useState<'generate' | 'style' | 'animate'>('generate');
    //const [ prompt, setPrompt ] = useState(DEFAULT_GENERATE_PROMPT);
    const [ promptGenerate, setPromptGenerate ] = useState(DEFAULT_GENERATE_PROMPT);
    const [ promptStyle, setPromptStyle ] = useState('');
    const [ promptAnimate, setPromptAnimate ] = useState(DEFAULT_ANIMATE_PROMPT);
    const [ loading, setLoading ] = useState(false);
    const [ error, setError ] = useState<string | null>(null); 

    const [ isDropdownOpen, setIsDropdownOpen ] = useState(false);

    const currentInnerBlocks = useSelect(
        ( select:any ) => select( 'core/block-editor' ).getBlocks( clientId ),
        [ clientId ]
    );
    const { replaceInnerBlocks } = useDispatch( 'core/block-editor' );

    function onSubmitPrompt(){
        switch(action) {
            case 'generate':
                handleGenerateNewBlocks();
                break;
            case 'style':
                handleStyleBlocks();
                break;                
            case 'animate':
                handleAnimateBlocks();
                break;
            default:
                console.error('Unknown action:', action);
                alert ('Unknown action: ' + JSON.stringify(action));
        }
    }

    async function handleGenerateNewBlocks(){
        console.log('handleGenerateBlocks called promptGenerate',promptGenerate);

        setError(null);
        setLoading(true);

        const allAvailableBlocks = getBlockTypes() // ~ 1MB
        const allBlockTypes = allAvailableBlocks.map( ( blockType:any ) => { // 300kb on a "fresh" install
            return {
                name: blockType.name,
                attributes: blockType.attributes,
                example: blockType.example,
            };
        });
        console.log(' All available blocks allAvailableBlocks:',allAvailableBlocks, 'allBlockTypes:', allBlockTypes);


        try {
            const res = await fetch(`${scroll_sequence_editor_data.scrollSequenceApiUrl}/v2/generate/blocks002`, { // generate blocks
                method: 'POST',
                headers: { 
                    'Content-Type': 'application/json', 
                    'Authorization': `${scroll_sequence_editor_data.fs_auth_hash}`,
                },
                body: JSON.stringify({ 
                    prompt: promptGenerate, // user generated prompt
                    blocks: currentInnerBlocks, // current InnerBlocks
                    allBlockTypes, // all available block types with only necessary data
                }),
            });

            let data;
            try {
                data = await res.json();
                console.log('AI response data:', data); 
            } catch (jsonErr) {
                throw new Error('Failed to parse API response as JSON.');
            }

            if (!res.ok) {
                // Prefer error message from API if available
                throw new Error(data?.error || `API error: ${res.status} ${res.statusText}`);
            }

            if (!data.newObject) {
                throw new Error('API did not return any block content.');
            }

            console.log('AI generated blocks:', data.newObject.blocks);

            // !!!! TODO: Make sure this works, currently it does not. 

            const blockObjects = data.newObject.blocks.map((b:any) => blueprintToBlock(b));
            console.log('AI generated blockObjects:', blockObjects);

            replaceInnerBlocks( clientId, blockObjects, false );


        } catch (err: any) {
            setError(err.message || 'Unknown error occurred.');
        } finally {
            setLoading(false);
        }
    }
    function blueprintToBlock(b:any) {
        // !!! THIS FUNCTION IS DUPLICATED IN CONTAINER BLOCKS AS WELL AS SCENE BLOCKS, IN REALITY I DONT KNOW IF WE NEED IT AT ALL
        console.log('blueprintToBlock b:', b);
       
        const { 
            name, 
            attrs = {}, 
            anim = {}, 
            children = [], 
            html 
        } = b;

         console.log('blueprintToBlock attrs', attrs);

        const animAttrs = {
            ssqAnimateOnLoad:  anim.onLoad,
            ssqAnimateOnClick: anim.onClick,
            ssqAnimateOnHover: anim.onHover,
            ssqAnimateOnScroll:anim.onScroll,
        };

        const wpBlock = createBlock(
            name,
            { ...attrs, ...animAttrs },
            children.map(blueprintToBlock)
        );

        if (html) wpBlock.originalContent = html;   // optional instant preview
        return wpBlock;
    }


    async function handleStyleBlocks(){
        console.log('handleStyleBlocks called promptStyle:', promptStyle);
        // Logic to style blocks based on the prompt
    }

    async function handleAnimateBlocks(){
        console.log('handleAnimateBlocks called with promptAnimate:', promptAnimate);
        setError(null);
        setLoading(true);

        try {

            const res = await fetch(`${scroll_sequence_editor_data.scrollSequenceApiUrl}/v2/generate/blocksanim002`, { // generate animations on existing blocks
                method: 'POST',
                headers: { 
                    'Content-Type': 'application/json', 
                    'Authorization': `${scroll_sequence_editor_data.fs_auth_hash}`,
                },
                body: JSON.stringify({ 
                    prompt: promptAnimate, // user generated prompt
                    blocks: currentInnerBlocks,
                }),
            });

            let data;
            try {
                data = await res.json();
                console.log('AI response data:', data); 
            } catch (jsonErr) {
                throw new Error('Failed to parse API response as JSON.');
            }

            if (!res.ok) {
                // Prefer error message from API if available
                throw new Error(data?.error || `API error: ${res.status} ${res.statusText}`);
            }

            if (!data.newObject) {
                throw new Error('API did not return any block content.');
            }

            const receivedBlocksAttributes = data.devData.step2Result.object.blocks
            console.log('AI updated blocks attributes:', receivedBlocksAttributes);
            // update attributes for each block  wp.data.dispatch('core/block-editor').updateBlockAttributes(clientId, updatedAttributes);
            receivedBlocksAttributes.forEach((block:any) => {
                const { clientId, ...attributes } = block;
                console.log('Updating block attributes for clientId:', clientId, 'with attributes:', attributes);
                // change null values (AI wants to delete animation) to undefined 
                Object.keys(attributes).forEach(key => {
                    if (attributes[key] === null) {
                        attributes[key] = undefined; // remove the attribute
                    }
                });
                console.log('Final attributes to update:', attributes);
                // Get the current block attributes
                // @ts-ignore
                const currentAttributes = wp.data.select('core/block-editor').getBlockAttributes(clientId);
                // Merge the new attributes with the current ones
                const updatedAttributes = { ...currentAttributes, ...attributes };

                // Update the block attributes
                // @ts-ignore
                wp.data.dispatch('core/block-editor').updateBlockAttributes(clientId, updatedAttributes);
            });

        } catch (err: any) {
            setError(err.message || 'Unknown error occurred.');
        } finally {
            setLoading(false);
        }
    }


    return (
        <>
            <ToolbarGroup>
                <Dropdown
                    popoverProps={ { placement: 'bottom-start' } }
                    isOpen={isDropdownOpen}
                    onToggle={() => setIsDropdownOpen(!isDropdownOpen)}
                    renderToggle={({ onToggle }:any) => (
                        <ToolbarButton
                            icon="format-chat"
                            label={__("Chat with AI", 'scrollsequence')}
                            onClick={onToggle}
                            isPressed={isDropdownOpen}
                        />
                    )}
                    renderContent={() => (
                        <>
                            <ToggleGroupControl
                                label={__("Select Action", 'scrollsequence')}
                                style={{ marginTop: 16}}
                                value={action}
                                onChange={ (newValue:any)=> {setAction(newValue)} }
                                isBlock
                                __nextHasNoMarginBottom
                                __next40pxDefaultSize
                            >
                                <ToggleGroupControlOption value="generate" label="Generate" showTooltip aria-label={__("Generate new and edit existing blocks", 'scrollsequence')} />
                                <ToggleGroupControlOption value="style" label="Style" />
                                <ToggleGroupControlOption value="animate" label="Animate" showTooltip aria-label={__("Animate Existing Blocks", 'scrollsequence')} />
                            </ToggleGroupControl>                        
                            <div style={{ width: 300, padding: 8 }}>
                                { action === 'generate' && (
                                    <TextareaControl
                                        label={__("Describe the Inner Blocks you want to generate", 'scrollsequence')}
                                        value={promptGenerate}
                                        onChange={setPromptGenerate}
                                        rows={4}
                                        disabled={loading}
                                    />
                                )}
                                { action === 'style' && (
                                    <TextareaControl
                                        label={__("Describe the style changes you want to apply", 'scrollsequence')}
                                        value={promptStyle}
                                        onChange={setPromptStyle}
                                        rows={4}
                                        disabled={true} // styling not implemented yet
                                    />
                                )}

                                

                                { action === 'animate' && (
                                    <>
                                    <NoticeTracking />
                                    <TextareaControl
                                        label={__("Describe the animations you want to generate on existing Inner Blocks.", 'scrollsequence')}
                                        value={promptAnimate}
                                        onChange={setPromptAnimate}
                                        rows={4}
                                        disabled={loading}
                                    />
                                    </>
                                )}                                



                                {action === 'generate' && (
                                    <>
                                        <NoticeTracking />
                                        <Notice status="info" isDismissible={false}>
                                            {__("Currently you can only generate Inner Blocks. AI Agent is unable to modify current block.", 'scrollsequence')}
                                            <br/>
                                            {__("If you have existing Inner Blocks, they may be removed or modified. Use undo (Ctrl+Z) to revert changes if needed.", 'scrollsequence')}
                                        </Notice>
                                    
                                    </>
                                )}


                                {action === 'style' && (
                                    <Notice status="warning" isDismissible={false}>
                                        {__("Generating styles is not possible yet, thank you for your patience.", 'scrollsequence')}
                                    </Notice>
                                )}

                                <Button
                                    variant="primary"
                                    icon={ loading ? <Spinner /> : undefined}
                                    onClick={ ()=> {
                                        onSubmitPrompt()
                                    } }
                                    disabled={loading || action === 'style' || (action === 'generate' && promptGenerate.trim() === '') || (action === 'animate' && promptAnimate.trim() === '') }
                                    style={{ marginTop: '0.5em' }}
                                    isBusy={loading}
                                >
                                    { loading ? __("Generating...", 'scrollsequence') : __("Ask AI", 'scrollsequence')}
                                </Button>
                                {error && (
                                    <div style={{
                                        marginTop: 12,
                                        color: '#d63638',
                                        background: '#fff0f1',
                                        border: '1px solid #d63638',
                                        borderRadius: 4,
                                        padding: 8,
                                        fontSize: 13,
                                    }}>
                                        <strong>{__("Error", 'scrollsequence')}:</strong> {error}
                                    </div>
                                )}
                            </div>
                        </>
                    )}
                />
            </ToolbarGroup>
        </>
    )
}