import React from "react";
import { useState, useEffect, useContext } from "react";

import { useImg2ImgState } from "./tools/img2img/useImg2ImgState";
import { useImg2VidState } from "./tools/img2vid/useImg2VidState";
import { useVid2SsqState } from "./tools/vid2ssq/useVid2SsqState";


// Top level types
import type { 
  IoNames, 
  ToolIds, 

  ToolsContextType,
  ToolImg2ImgContextState,
  ToolImg2VidContextState,
  ToolVid2SsqContextState,
  
  Busy, LogEntry,  UpdateProgressParams,

  OutputType,
  OutputHistoryType

} from "./types";

import { useOutputsStore } from './outputsStore';

const ToolsContext = React.createContext<ToolsContextType | undefined>(undefined);

// H - E - L - P - E - R - S
// TOP LEVEL
export function useToolsContext() { // top level context
  const ctx = useContext(ToolsContext);
  if (!ctx) throw new Error("ToolsContext missing");
  return ctx;
}
// TOOLS LEVEL
export function useImg2ImgContext() { // img2img context
  const ctx = useContext(ToolsContext);
  if (!ctx) throw new Error("ToolsContext missing");
  return ctx.tools.find(tool => tool.id === "img2img") as ToolImg2ImgContextState ;
}
export function useImg2VidContext() { // img2vid context
  const ctx = useContext(ToolsContext);
  if (!ctx) throw new Error("ToolsContext missing");
  return ctx.tools.find(tool => tool.id === "img2vid") as ToolImg2VidContextState;
}
export function useVid2SsqContext() { // vid2ssq context
  const ctx = useContext(ToolsContext);
  if (!ctx) throw new Error("ToolsContext missing");
  return ctx.tools.find(tool => tool.id === "vid2ssq") as ToolVid2SsqContextState;
}
// add more tools here 
// MODELS LEVEL


export default function ToolsContextProvider({
  children,
  //value
}: {
  children: React.ReactNode,
  //value: {  }
}) {
  // TOP LEVEL STATES
  const [ activeIo, setActiveIo ] = useState<IoNames>('input');
  const [ activeToolId, setActiveToolId ] = useState<ToolIds>('img2img');
  

  // TOOL STATES
  const tools : ToolsContextType['tools'] = [
    useImg2ImgState(),
    useImg2VidState(), 
    useVid2SsqState(),
    // add more tools here
  ]


  // PROGRESS main states
  const [ busy, setBusyDoNotUseThisIsInternal ] = useState<Busy>(false); 
  const [ log, setLogDoNotUseThisIsInternal] = useState<LogEntry[]>([]);
  function updateProgress({
    busy, 
    log // newly added log entry
  }: UpdateProgressParams ) {
    //console.log('updateProgress() called with:', { busy, log });
    if (busy !== undefined) { // update busy state
      setBusyDoNotUseThisIsInternal( ( prev ) => busy );
    }
    if (log !== undefined) { // update log state
      setLogDoNotUseThisIsInternal((prev) => {
        const newLogs: LogEntry[] =           [
            ...prev,
            { 
              timestamp: Date.now(), 
              level: log.level, 
              message: log.message, 
              data: log?.data
            }
          ]
        if (log.level === 'error') { // If log level is 'error', also do something special.
          console.log('Progress Log Error! log:(latest)', log, ' newLogs:(all)', newLogs);
        }
        return (
          newLogs
        )
      });
    }
  }


  // OUTPUT STATES
  console.log('0ToolsContextProvider rendering, calling useOutputsStore()');
  const { outputs, addOutput, refresh, invalidate, errorOutputs } = useOutputsStore();
  const [ outputActiveIndex, setOutputActiveIndex ] = useState<number>(-1); // -1 means none selected
  const [ outputActiveSubIndex, setOutputActiveSubIndex ] = useState<number>(0);

  // each time outputsActiveIndex changes, reset subindex to 0
  useEffect(() => {
    setOutputActiveSubIndex(0);
  }, [outputActiveIndex]);
  
  // optionally expose errorOutputs via context or log it
  // useEffect(() => {
  //   if (errorOutputs) {
  //     console.warn('Outputs fetch errorOutputs:', errorOutputs);
  //   }
  // }, [errorOutputs]);
  //console.log('CONTEXT PROVIDER OUTPUT STORE errorOutputsS:', errorOutputs);

  return (
    <ToolsContext.Provider
      value={{
        activeIo, setActiveIo,
        activeToolId, setActiveToolId,
        

        tools,

        progress: {
          busy,
          log,
          updateProgress,
        },

        outputs, addOutput,
        outputActiveIndex, setOutputActiveIndex,
        outputActiveSubIndex, setOutputActiveSubIndex,
        refreshOutputs: async (force = false) => { await refresh?.(force); },
        invalidateOutputs: () => invalidate?.(),       
        errorOutputs, 
      }}
    >
      {children}
    </ToolsContext.Provider>
  );
}


