import { createContext, useState } from "react";
import type { Project } from "../types/project";
import type { Screen } from "../types/screen";
import type { UIData, Component, GeneralData, ButtonGeneralData, TextGeneralData, TextFieldGeneralData, TableGeneralData } from "../types/component";
import { ComponentType } from "../types/component";
import type { Table } from "../types/table";

function getInitialGeneralData(type: ComponentType): GeneralData {
    switch (type) {
        case ComponentType.Text:
            return { text: "text" }
        case ComponentType.Button:
            return { text: "button" }
        case ComponentType.TextField:
            return { text: "text field" }
        case ComponentType.Table:
            return { referenceTableName: "", columns: [] }
    }
}

export interface ProjectStates {
    project: Project,
    screens: Screen[],
    tables: Table[]
}

export interface ProjectActions {
    updateProject: (project: Project) => void
    addScreen: (name: string) => string
    updateScreen: (screen: Screen) => void
    deleteScreen: (screenId: string) => void
    addComponent: (screenId: string, type: ComponentType) => void
    addComponents: (screenId: string, components: Component[]) => void
    updateComponent: (component: Component) => void
    moveComponent: (screenId: string, componentId: string, uiData: UIData) => void
    deleteComponent: (screenId: string, componentId: string) => void
    addTable: (table: Table) => void
    updateTable: (table: Table) => void
    deleteTable: (tableId: string) => void
}

export interface ProjectStatesAndActions {
    projectStates: ProjectStates
    projectActions: ProjectActions
}

export function useProject(initProject: Project = {
    id: "",
    title: "",
    detail: "",
    createdTime: "",
    updatedTime: "",
    screens: [
        {
            id: "screen1",
            components: [],
            index: 0,
            name: "screen1",
            projectId: ""
        }
    ],
    tables: []
}): ProjectStatesAndActions {

    const [project, setProject] = useState<Project>(initProject);
    const screens = project.screens;
    const tables = project.tables;

    const updateProject = (project: Project) => {
        setProject(project);
    }

    const addScreen = (name: string) => {
        const nextIndex = screens[screens.length - 1].index + 1;
        const newScreenId = "screen" + nextIndex;
        const newScreen: Screen = {
            id: newScreenId,
            components: [],
            index: nextIndex,
            name: name,
            projectId: project.id
        }
        setProject(prev => ({ ...prev, screens: [...prev.screens, newScreen] }));
        return newScreenId;
    }

    const deleteScreen = (screenId: string) => {
        setProject(prev => ({ ...prev, screens: prev.screens.filter(s => s.id !== screenId) }));
    }

    const updateScreen = (screen: Screen) => {
        setProject(prev => ({ ...prev, screens: prev.screens.map(s => s.id === screen.id ? screen : s) }));
    }

    const addComponent = (screenId: string, type: ComponentType) => {
        const screen = screens.find(s => s.id === screenId);
        if (!screen) {
            return;
        }
        const nextIndex = screen.components.length > 0 ? screen.components[screen.components.length - 1].index + 1 : 0;
        const uiData: UIData = {
            posX: 100,
            posY: 100,
            width: 75,
            height: 25
        };
        const newId = screen.id + "Widget" + nextIndex;
        let newComponent: Component;
        switch (type) {
            case ComponentType.Button:
                newComponent = {
                    id: newId,
                    name: newId,
                    type: type,
                    index: nextIndex,
                    screenId: screen.id,
                    generalData: getInitialGeneralData(type) as ButtonGeneralData,
                    style: {},
                    uiData: uiData,
                }
                break;
            case ComponentType.Text:
                newComponent = {
                    id: newId,
                    name: newId,
                    type: type,
                    index: nextIndex,
                    screenId: screen.id,
                    generalData: getInitialGeneralData(type) as TextGeneralData,
                    style: {},
                    uiData: uiData,
                }
                break;
            case ComponentType.TextField:
                newComponent = {
                    id: newId,
                    name: newId,
                    type: type,
                    index: nextIndex,
                    screenId: screen.id,
                    generalData: getInitialGeneralData(type) as TextFieldGeneralData,
                    style: {},
                    uiData: uiData,
                }
                break;
            case ComponentType.Table:
                newComponent = {
                    id: newId,
                    name: newId,
                    type: type,
                    index: nextIndex,
                    screenId: screen.id,
                    generalData: getInitialGeneralData(type) as TableGeneralData,
                    style: {},
                    uiData: uiData,
                }
                break;
        }
        setProject(prev => (
            {
                ...prev,
                screens: prev.screens.map((s, i) => s.id === screenId ? {
                    ...prev.screens[i],
                    components: [...prev.screens[i].components, newComponent]
                } : s)
            }
        ))
    }

    const addComponents = (screenId: string, components: Component[]) => {
        setProject(prev => (
            {
                ...prev,
                screens: prev.screens.map((s, i) => s.id === screenId ? {
                    ...prev.screens[i],
                    components: [...prev.screens[i].components, ...components]
                } : s)
            }
        ))
    }

    const moveComponent = (screenId: string, componentId: string, uiData: UIData) => {
        setProject(prev => (
            {
                ...prev,
                screens: prev.screens.map((s, i) => s.id === screenId ? {
                    ...prev.screens[i],
                    components: prev.screens[i].components.map((c, j) => c.id === componentId ? {
                        ...prev.screens[i].components[j],
                        uiData: uiData
                    } : c)
                } : s)
            }
        ))
    }

    const updateComponent = (component: Component) => {
        setProject(prev => (
            {
                ...prev,
                screens: prev.screens.map((s, i) => s.id === component.screenId ? {
                    ...prev.screens[i],
                    components: prev.screens[i].components.map(c => c.id === component.id ? component : c)
                } : s)
            }
        ))
    }

    const deleteComponent = (screenId: string, componentId: string) => {
        setProject(prev => (
            {
                ...prev,
                screens: prev.screens.map((s, i) => s.id === screenId ? {
                    ...prev.screens[i],
                    components: prev.screens[i].components.filter(c => c.id !== componentId)
                } : s)
            }
        ))
    }

    const addTable = (table: Table) => {
        setProject(prev => ({
            ...prev,
            tables: [...prev.tables, table]
        }))
    }

    const updateTable = (table: Table) => {
        setProject(prev => ({
            ...prev,
            tables: prev.tables.map(t => t.id === table.id ? table : t)
        }));
    }

    const deleteTable = (tableId: string) => {
        setProject(prev => ({
            ...prev,
            tables: prev.tables.filter(table => table.id !== tableId)
        }))
    }

    return {
        projectStates: { project, screens, tables },
        projectActions: {
            updateProject,
            addScreen,
            updateScreen,
            deleteScreen,
            addComponent,
            addComponents,
            updateComponent,
            moveComponent,
            deleteComponent,
            addTable,
            updateTable,
            deleteTable
        }
    }


}


export const ProjectContext = createContext<ProjectStatesAndActions | null>(null);
