import { JupyterFrontEnd } from '@jupyterlab/application';
import { app, functions } from './jupyter_integrations'

import {streamingState} from "./jupyter_integrations"

export async function ensurePathExists (
    app: JupyterFrontEnd,
    fullPath: string
  ): Promise<void> {
    const contents = app.serviceManager.contents;
    const parts = fullPath.split('/');
    parts.pop(); // remove file name
  
    let currentPath = '';
    for (const part of parts) {
      currentPath = currentPath ? `${currentPath}/${part}` : part;
  
      try {
        const stat = await contents.get(currentPath);
        if (stat.type !== 'directory') {
          throw new Error(`${currentPath} exists but is not a directory`);
        }
      } catch (err: any) {
        if (err?.response?.status === 404 || /not found/i.test(err.message)) {
          // Create the directory using contents.save()
          await contents.save(currentPath, {
            type: 'directory',
            format: 'json',
            content: null
          });
        } else {
          throw new Error(`Failed checking/creating directory ${currentPath}: ${err.message}`);
        }
      }
    }
  }

export function init_fs() {
    functions["listFiles"] = {
    "def": {
        "name": "listFiles",
        "description": "List files and directories at a specified relative path. Ignore rootPath if it exists",
        "arguments": {
        "path": {
            "type": "string",
            "name": "Relative path to list files from. Relative!",
            "default": "/"
        }
        }
    },
    "func": async (args: any): Promise<string> => {
        if (!app) {
        return JSON.stringify({ error: "JupyterLab app not initialized" });
        }
        
        const path = args.path || '/';
        const contents = app.serviceManager.contents;
        
        try {
        const listing = await contents.get(path, { content: true });
        
        if (listing.type !== 'directory') {
            return JSON.stringify({ 
            error: `Path '${path}' is not a directory` 
            });
        }
        
        const files = listing.content.map(item => ({
            name: item.name,
            path: item.path,
            type: item.type,
            last_modified: item.last_modified
        }));
        
        return JSON.stringify({ 
            success: true,
            files: files
        });
        } catch (error) {
        return JSON.stringify({ 
            error: `Error listing files: ${error.message}` 
        });
        }
    }
    }

    functions["writeToFile"] = {
        "def": {
        "name": "writeToFile",
        "description": "Opens a non-notebook file for editing (code, text, etc) and write into it",
        "arguments": {
            "filePath": {
            "type": "string",
            "name":  "Relative path to the file to open. Relative! "
            },
            "content": {
            "type": "string",
            "name":  "New content for the file. Entire file is being replaced by this!"
            }
        }
        },
        "func": async (args: any, streaming:boolean=false, call_id:string=undefined): Promise<string> => {
            if (!app) {
                return JSON.stringify({ error: "JupyterLab app not initialized" });
            }
            const { contents } = app.serviceManager;
            const {filePath, content} = args;

            if (call_id == undefined) return "dummy ok";

            // create the file if nessesary
            await ensurePathExists(app, filePath);


            /*
            try {
                try {
                    await contents.get(filePath);
                } catch {
                    await contents.save(filePath, {
                        type: 'file',
                        format: 'text',
                        content: ''
                    });
                }
            } catch (err) {
                return JSON.stringify({"status":"fail", "message":"could not open file",
                    "detail": `${err.message}`
                });
            }
            */
            await contents.save(filePath, {
                type: 'file',
                format: 'text',
                content: content
            });


            let widget;
            try {
                widget = await app.commands.execute('docmanager:open', {
                    path: filePath,
                    factory: 'Editor'
                });
            } catch (err) {
                return JSON.stringify({"status":"fail", "message":"could not open file",
                    "detail": `${err.message}`
                });
            }
            
            try {
                await Promise.race([
                    widget.context.ready,
                    new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout waiting for context.ready')), 500))
                ]);
            } catch (err) {
                return JSON.stringify({"status":"fail", "message":"could not open file"});
            }

            await widget.context.revert();

            //widget.content.model.sharedModel.setSource( content );
            //await widget.context.save();

            // Return current live content in the editor (unsaved edits included)
            return JSON.stringify ({
                "status": "ok"
            })
        }
        }


    functions["openFile"] = {
        "def": {
            "name": "openFile",
            "description": "Opens a non-notebook file for editing (code, text, etc) and returns its contents",
            "arguments": {
            "filePath": {
                "type": "string",
                "name":  "Relative path to the file to open. Relative! "
            }
            }
        },
        "func": async (args: any): Promise<string> => {
            if (!app) {
                return JSON.stringify({ error: "JupyterLab app not initialized" });
            }
            const filePath = args["filePath"]

            const { contents } = app.serviceManager;
            let fileContent;

            // Ensure file exists (create if it doesn't)
            await ensurePathExists(app, filePath);
            try {
                try {
                    fileContent = await contents.get(filePath);
                } catch {
                    await contents.save(filePath, {
                        type: 'file',
                        format: 'text',
                        content: ''
                    });
                    fileContent = await contents.get(filePath);
                }
            } catch (err) {
                return JSON.stringify({"status":"fail", "message":"could not open file",
                    "detail": `${err.message}`
                });
            }

            let widget;
            try {
                widget = await app.commands.execute('docmanager:open', {
                    path: filePath,
                    factory: 'Editor'
                });
            } catch (err) {
                return JSON.stringify({"status":"fail", "message":"could not open file",
                    "detail": `${err.message}`
                });
            }

            try {
                await Promise.race([
                    widget.context.ready,
                    new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout waiting for context.ready')), 500))
                ]);
            } catch (err) {
                    return JSON.stringify({"status":"fail", "message":"could not open file"});
            }

            const result = JSON.stringify({
                "status": "ok",
                "content": fileContent.content
            });

            console.log("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
            console.log(result);

            return (result);
        }
    }

}
