import {stripHtml, strKeywordSearch} from "../../utils";
import {ConfigRow, SectionTables} from "./types";
import {Item} from "../AccordionGroup";

/**
 * Nested item data.
 * Theme -> Section -> Config setting
 * e.g.
 * "Assessment" -> "CAPs" -> CAPS_GRADE_DESCRIPTION
 */
export interface ThemeItem extends Item {
    sections:  {
        [key: string]: SectionItem // Key is section id
    }
}
export interface SectionItem extends Item {
    tableOpen: string,
    tableClose: string,
    configSettings: {
        [key: string]: { // key: Config name/reference
            visible: boolean,
            html: string,
            helpText: string,
        }
    }
}

interface DataStore { 
    [theme: string]: ThemeItem 
}

export class ConfigData
{
    protected dataStore: DataStore = {};
    
    public constructor(configRows: ConfigRow[] = [], sectionTables: SectionTables = {}) 
    {
        let nestedData: DataStore = {};
        // Define themes:
        for (let row of configRows) {
            nestedData[row.theme] = {header: row.theme, visible: true, expanded: false, sections: {}};
        }
        // Define sections:
        for (let row of configRows) {
            nestedData[row.theme].sections[row.section] = {
                header: row.section,
                visible: true,
                expanded: false,
                configSettings: {},
                tableOpen: sectionTables[row.section],
                tableClose: '</table>'
            }
        }
        // Define config keys:
        for (let row of configRows) {
            nestedData[row.theme].sections[row.section].configSettings[row.configKey] = {
                visible: true,
                html: row.html,
                helpText: stripHtml(row.helpText)
            }
        }
        this.setDataStore(nestedData);
    }

    public isEmpty(): boolean 
    {
        for (let [themeKey,theme] of Object.entries(this.dataStore)) {
            if (theme.visible){
                return false;
            }
        }
        return true;
    }
    
    public getDataStore(): DataStore
    { 
        return this.dataStore;
    }
    
    /**
     * Apply a keyword search filter, and return a new ConfigData instance.
     * @param keywordStr
     */
    public configSearch(keywordStr: string): ConfigData 
    {
        const newDataStore = structuredClone(this.getDataStore());

        // todo rcp Behaviour: One row returned -> always auto expand.
        for (const theme of Object.values(newDataStore)) {
            let themeKey = theme.header;
            let sectionAcc = false;
            theme.visible = strKeywordSearch(themeKey, keywordStr);
            theme.expanded = theme.visible;

            for (const section of Object.values(theme.sections)) {
                let sectionKey = section.header;
                let cfgAcc = false;
                section.visible = strKeywordSearch([sectionKey,themeKey].join(' '), keywordStr) || theme.visible;
                section.expanded ||= strKeywordSearch([sectionKey, themeKey].join(' '), keywordStr)

                for (const [cfgKey, cfg] of Object.entries(section.configSettings)) {
                    cfg.visible = strKeywordSearch([themeKey, sectionKey, cfgKey, cfg.helpText].join(' '), keywordStr) || section.visible;
                    cfgAcc ||= cfg.visible;
                    section.expanded ||= strKeywordSearch([themeKey, sectionKey, cfgKey, cfg.helpText].join(' '), keywordStr);
                }

                section.visible ||= cfgAcc;
                sectionAcc ||= section.visible;
                theme.expanded ||= section.expanded;
            }

            theme.visible ||= sectionAcc;
        }
        return new ConfigDataPreloaded(newDataStore);
    }

    /**
     * @protected This object is **immutable**. 
     */
    protected setDataStore(d: DataStore): void 
    {
        this.dataStore = d;
    }
}

class ConfigDataPreloaded extends ConfigData
{
    public constructor(preloadData: DataStore) {
        super();
        this.setDataStore(preloadData);
    }
}
