import { useState, useEffect, useCallback } from 'react';
import AsyncStorage from '@react-native-async-storage/async-storage';
import * as FileSystem from 'expo-file-system';
import { DATA_DIRECTORY_URI_KEY } from '@/constants/Settings';
import { StorageAccessFramework } from 'expo-file-system';
import { format } from 'date-fns';

interface FileEntry {
    name: string;
    uri: string;
    datetime: Date;
    size: number;
}
interface PrettyNameOptions {
    pathContext?: 'full' | 'short';
}
interface FileInfoWithSize {
    uri: string;
    exists: boolean;
    isDirectory: boolean | null;
    modificationTime: number | null;
    size: number;
}

function datetimeFromFilename(filename: string): string {
    const match = filename.match(/(\d+)-(\d+)-(\d+)-(\d+)-(\d+)-(\d+)\.md$/);
    if (match) {
        const [_, year, month, day, hour, minute, second] = match;
        return new Date(
            parseInt(year),
            parseInt(month) - 1,
            parseInt(day),
            parseInt(hour),
            parseInt(minute),
            parseInt(second)
        ).toISOString();
    }
    return new Date().toISOString();
}

export function prettyName(uri: string | null, options: PrettyNameOptions = {}) {
    if (!uri) return null;
    const { pathContext = 'short' } = options;

    var returnString = "";
    if (pathContext === 'full') {
        returnString = "/";
    }

    const decodedUri = decodeURIComponent(uri);
    const match = decodedUri.match(/.*\/primary:(.+)/);

    if (match) {
        if (pathContext === 'short') {
            const filename = match[1].split('/').pop() || "Unknown";
            returnString = returnString.concat(filename);
        }
        else {
            returnString = returnString.concat(match[1]);
        }
    }
    else {
        // Fallback to your original logic
        returnString = returnString.concat(uri.split('%3A').pop() || "Unknown");
    }
    return returnString;
}

export function useFileSystem() {
    const [dataDirectoryUri, setDataDirectoryUri] = useState<string | null>(null);
    const [isLoading, setIsLoading] = useState(true);
    const [files, setFiles] = useState<FileEntry[]>([]);
    const [directorySize, setDirectorySize] = useState<number>(0);

    // Load saved directory URI
    useEffect(() => {
        const loadDirectoryUri = async () => {
            try {
                const savedUri = await AsyncStorage.getItem(DATA_DIRECTORY_URI_KEY);
                if (savedUri) {
                    setDataDirectoryUri(savedUri);
                }
            } catch (error) {
                console.error('Error loading directory URI:', error);
            } finally {
                setIsLoading(false);
            }
        };

        loadDirectoryUri();
    }, []);

    // Load files when directory changes
    const loadFiles = useCallback(async () => {
        if (!dataDirectoryUri) return;


        try {
            const dirContents = await StorageAccessFramework.readDirectoryAsync(dataDirectoryUri);
            const markdownFiles = [];
            let totalSize = 0;

            for (const fileName of dirContents.filter(name => name.endsWith('.md'))) {
                try {
                    const fileInfo = await FileSystem.getInfoAsync(fileName) as FileInfoWithSize;
                    const fileEntry = {
                        name: prettyName(fileName) ?? "",
                        uri: fileInfo.uri,
                        datetime: datetimeFromFilename(fileName),
                        size: fileInfo.size,
                    };

                    markdownFiles.push(fileEntry);
                    totalSize += fileEntry.size;
                } catch (error) {
                    console.warn(`Error getting info for file ${fileName}:`, error);
                }
            }
            markdownFiles.sort((a, b) => b.datetime.getTime() - a.datetime.getTime()); // Sort by datetime descending
            setFiles(markdownFiles);
            setDirectorySize(totalSize);
        } catch (error) {
            console.error('Error loading files:', error);
        }
    }, [dataDirectoryUri]);

    useEffect(() => {
        loadFiles();
    }, [loadFiles]);

    const writeFile = useCallback(async (fileUriOrDatetime: string, content: string) => {
        if (!dataDirectoryUri) throw new Error('No directory selected');
        const fileUriDatetime = new Date(parseInt(fileUriOrDatetime) * 1000);
        let fileUri = fileUriOrDatetime;
        if (parseInt(fileUriOrDatetime)) { // If it's a datetime in seconds
            const filename = format(fileUriDatetime, 'yyyy-MM-dd-HH-mm-ss');
            fileUri = await StorageAccessFramework.createFileAsync(
                dataDirectoryUri,
                `${filename}.md`,
                'text/markdown'
            );
        }
        // const fileUri = `${dataDirectoryUri}/${filename}`;
        await FileSystem.writeAsStringAsync(fileUri, content);
        await loadFiles(); // Refresh file list
    }, [dataDirectoryUri, loadFiles]);

    const readFile = useCallback(async (filename: string): Promise<string> => {
        if (!dataDirectoryUri) throw new Error('No directory selected');

        const fileUri = `${dataDirectoryUri}/${filename}`;
        return await FileSystem.readAsStringAsync(fileUri);
    }, [dataDirectoryUri]);

    const deleteFile = useCallback(async (filename: string): Promise<void> => {
        return await FileSystem.deleteAsync(filename, { idempotent: true });
    }
        , []);

    const saveDataDirectoryUri = useCallback(async (uri: string | null) => {
        try {
            if (uri) {
                await AsyncStorage.setItem(DATA_DIRECTORY_URI_KEY, uri);
            } else {
                await AsyncStorage.removeItem(DATA_DIRECTORY_URI_KEY);
            }
            setDataDirectoryUri(uri);
            // Refresh files when directory changes
            if (uri) {
                await loadFiles();
            } else {
                setFiles([]);
            }
        } catch (error) {
            console.error('Error updating directory URI:', error);
        }
    }, [loadFiles]);

    return {
        dataDirectoryUri,
        saveDataDirectoryUri,
        isLoading,
        files,
        writeFile,
        readFile,
        deleteFile,
        loadFiles,
        hasDirectory: !!dataDirectoryUri,
        directorySize,
    };
}