import { useState, useEffect } from '@wordpress/element';
import type { OutputHistoryType } from './types';

declare const scroll_sequence_editor_data: any;


class OutputsStore {
    private static instance: OutputsStore;
    private outputs: OutputHistoryType[] = [];
    private fetched = false; // whether we've successfully fetched at least once
    private inFlight: Promise<void> | null = null; // dedupe concurrent fetches
    // subscribers receive both outputs snapshot and current error (if any)
    private subscribers = new Set<(outs: OutputHistoryType[], err: any) => void>();
    private lastError: any = null;

    private constructor() {}

    public static getInstance(): OutputsStore {
        if (!OutputsStore.instance) {
            OutputsStore.instance = new OutputsStore();
        }
        return OutputsStore.instance;
    }

    // fetch outputs from server; if already fetched and force===false, return early
    public async fetch(force = false) {
        if (!force && this.fetched) return;
        // if already fetching, return same promise so callers dedupe
        if (this.inFlight) return this.inFlight;

        this.inFlight = (async () => {
            console.log('Fetching outputs from API... /v2/jobs?filter=media-tools');
            console.log('Fetching outputs from API... /v2/jobs?filter=media-tools');
            console.log('Fetching outputs from API... /v2/jobs?filter=media-tools');
            console.log('Fetching outputs from API... /v2/jobs?filter=media-tools');
            console.log('Fetching outputs from API... /v2/jobs?filter=media-tools');

            try {
                this.lastError = null;
                const res = await fetch(
                    `${scroll_sequence_editor_data.scrollSequenceApiUrl}/v2/jobs?filter=media-tools-outputs`,
                    {
                        method: 'GET',
                        headers: {
                            Authorization: `${scroll_sequence_editor_data.fs_auth_hash}`,
                            'Content-Type': 'application/json',
                        },
                    }
                );
                const json = await res.json();
                this.outputs = Array.isArray(json) ? json : [];
                this.fetched = true;
                this.notifySubscribers();

				console.log('Fetched outputs:', this.outputs);
				console.log('Fetched outputs:', this.outputs);
				console.log('Fetched outputs:', this.outputs);
				console.log('Fetched outputs:', this.outputs);
				console.log('Fetched outputs:', this.outputs);


            } catch (err) {
                // Extract error string 
                const errorMessage = err instanceof Error ? err.message : 'Error fetching outputs';
                this.lastError = errorMessage;
                console.error('OutputsStore.fetch() errorMessage:', errorMessage);
                // notify so UI can show error state if it wants
                this.notifySubscribers();
            } finally {
                this.inFlight = null;
            }
        })();
        return this.inFlight;
    }

    // mark cache stale so next fetch() will call the server
    public invalidate() {
        this.fetched = false;
    }

    public getError() {
        return this.lastError;
    }

    public getOutputs() {
        return this.outputs;
    }

    public addOutput(newOutput: OutputHistoryType) {
        // Add to head (newest first)
        this.outputs = [newOutput, ...this.outputs];
        // notify with current error (usually null)
        this.notifySubscribers();
    }

    public subscribe(setter: (outs: OutputHistoryType[], err: any) => void) {
        this.subscribers.add(setter);
        // immediately send current snapshot + error
        setter(this.outputs, this.lastError);
    }

    public unsubscribe(setter: (outs: OutputHistoryType[], err: any) => void) {
        this.subscribers.delete(setter);
    }

    private notifySubscribers() {
        this.subscribers.forEach((s) => {
            try {
                s(this.outputs, this.lastError);
            } catch (e) {
                // swallow subscriber errors
                console.error('OutputsStore.notifySubscribers error', e);
            }
        });
    }
}

// Export the singleton instance
export const outputsStore = OutputsStore.getInstance();

// React hook for using the store
export function useOutputsStore() {
     const [state, setState] = useState<OutputHistoryType[]>(outputsStore.getOutputs());
     const [error, setError] = useState<any>(outputsStore.getError());
 
     useEffect(() => {
        const setter = (outs: OutputHistoryType[], err: any) => {
            setState(outs);
            setError(err);
        };
        outputsStore.subscribe(setter);
        return () => outputsStore.unsubscribe(setter);
     }, []);
 
     return {
         outputs: state,
         addOutput: (o: OutputHistoryType) => outputsStore.addOutput(o),
         refresh: (force = false) => outputsStore.fetch(force),
         invalidate: () => outputsStore.invalidate(),
         errorOutputs: error,
     };
 }