import { UmbLogViewerRepository } from '../repository/log-viewer.repository.js';
import { UMB_APP_LOG_VIEWER_CONTEXT } from './logviewer-workspace.context-token.js';
import { UmbBasicState, UmbArrayState, UmbObjectState, UmbStringState } from '../../../libs/observable-api/index.js';
import { DirectionModel, LogLevelModel } from '../../core/backend-api/index.js';
import { UmbContextBase } from '../../../libs/class-api/index.js';
import { query } from '../../core/router/index.js';
import { UMB_WORKSPACE_CONTEXT } from '../../core/workspace/index.js';
import { UmbViewContext } from '../../core/view/index.js';
// TODO: Revisit usage of workspace for this case...
export class UmbLogViewerWorkspaceContext extends UmbContextBase {
    #repository;
    getEntityType() {
        return 'log-viewer';
    }
    get today() {
        const today = new Date();
        const dd = String(today.getDate()).padStart(2, '0');
        const mm = String(today.getMonth() + 1).padStart(2, '0');
        const yyyy = today.getFullYear();
        return yyyy + '-' + mm + '-' + dd;
    }
    get yesterday() {
        const yesterday = new Date(new Date().setDate(new Date().getDate() - 1));
        const dd = String(yesterday.getDate()).padStart(2, '0');
        const mm = String(yesterday.getMonth() + 1).padStart(2, '0');
        const yyyy = yesterday.getFullYear();
        return yyyy + '-' + mm + '-' + dd;
    }
    #savedSearches;
    #logCount;
    #dateRange;
    #loggers;
    #canShowLogs;
    #isLoadingLogs;
    #filterExpression;
    #messageTemplates;
    #logLevelsFilter;
    #logs;
    #polling;
    #sortingDirection;
    #intervalID;
    constructor(host) {
        super(host, UMB_APP_LOG_VIEWER_CONTEXT);
        this.workspaceAlias = 'Umb.Workspace.LogViewer';
        this.view = new UmbViewContext(this, null);
        this.defaultDateRange = {
            startDate: this.yesterday,
            endDate: this.today,
        };
        this.#savedSearches = new UmbObjectState(undefined);
        this.savedSearches = this.#savedSearches.asObservablePart((data) => data);
        this.#logCount = new UmbObjectState(null);
        this.logCount = this.#logCount.asObservable();
        this.#dateRange = new UmbObjectState(this.defaultDateRange);
        this.dateRange = this.#dateRange.asObservable();
        this.#loggers = new UmbObjectState(null);
        this.loggers = this.#loggers.asObservablePart((data) => data?.items);
        this.#canShowLogs = new UmbBasicState(null);
        this.canShowLogs = this.#canShowLogs.asObservable();
        this.#isLoadingLogs = new UmbBasicState(null);
        this.isLoadingLogs = this.#isLoadingLogs.asObservable();
        this.#filterExpression = new UmbStringState('');
        this.filterExpression = this.#filterExpression.asObservable();
        this.#messageTemplates = new UmbObjectState(null);
        this.messageTemplates = this.#messageTemplates.asObservable();
        this.#logLevelsFilter = new UmbArrayState([], (x) => x);
        this.logLevelsFilter = this.#logLevelsFilter.asObservable();
        this.#logs = new UmbObjectState(null);
        this.logs = this.#logs.asObservablePart((data) => data?.items);
        this.logsTotal = this.#logs.asObservablePart((data) => data?.total);
        this.#polling = new UmbObjectState({ enabled: false, interval: 2000 });
        this.polling = this.#polling.asObservable();
        this.#sortingDirection = new UmbBasicState(DirectionModel.DESCENDING);
        this.sortingDirection = this.#sortingDirection.asObservable();
        this.#intervalID = null;
        this.currentPage = 1;
        this.onChangeState = () => {
            const searchQuery = query();
            this.setFilterExpression(searchQuery.lq ?? '');
            let validLogLevels = [];
            if (searchQuery.loglevels) {
                const loglevels = searchQuery.loglevels.split(',');
                // Filter out invalid log levels that do not exist in LogLevelModel
                validLogLevels = loglevels.filter((loglevel) => {
                    return Object.values(LogLevelModel).includes(loglevel);
                });
            }
            this.setLogLevelsFilter(validLogLevels);
            const dateRange = this.getDateRange();
            this.setDateRange({
                startDate: searchQuery.startDate || dateRange.startDate,
                endDate: searchQuery.endDate || dateRange.endDate,
            });
            this.setCurrentPage(searchQuery.page ? Number(searchQuery.page) : 1);
            this.getLogs();
        };
        this.getLogs = async () => {
            if (this.#canShowLogs.getValue() === false) {
                return;
            }
            const isPollingEnabled = this.#polling.getValue().enabled;
            if (!isPollingEnabled)
                this.#isLoadingLogs.setValue(true);
            const skip = (this.currentPage - 1) * 100;
            const take = 100;
            const options = {
                skip,
                take,
                orderDirection: this.#sortingDirection.getValue(),
                filterExpression: this.#filterExpression.getValue(),
                logLevel: this.#logLevelsFilter.getValue(),
                ...this.#dateRange.getValue(),
            };
            const { data } = await this.#repository.getLogs(options);
            this.#isLoadingLogs.setValue(false);
            if (data) {
                this.#logs.setValue(data);
            }
        };
        // TODO: Revisit usage of workspace for this case... currently no other workspace context provides them self with their own token, we need to update UMB_APP_LOG_VIEWER_CONTEXT to become a workspace context. [NL]
        this.provideContext(UMB_WORKSPACE_CONTEXT, this);
        this.#repository = new UmbLogViewerRepository(host);
        this.view.setTitle('#treeHeaders_logViewer');
    }
    hostConnected() {
        super.hostConnected();
        window.addEventListener('changestate', this.onChangeState);
        this.onChangeState();
    }
    hostDisconnected() {
        super.hostDisconnected();
        window.removeEventListener('changestate', this.onChangeState);
        this.stopPolling();
    }
    setDateRange(dateRange) {
        let { startDate, endDate } = dateRange;
        if (!startDate)
            startDate = this.defaultDateRange.startDate;
        if (!endDate)
            endDate = this.defaultDateRange.endDate;
        const isAnyDateInTheFuture = new Date(startDate) > new Date() || new Date(endDate) > new Date();
        const isStartDateBiggerThenEndDate = new Date(startDate) > new Date(endDate);
        if (isAnyDateInTheFuture || isStartDateBiggerThenEndDate) {
            return;
        }
        this.#dateRange.setValue({ startDate, endDate });
        this.validateLogSize();
        this.getLogCount();
        this.getMessageTemplates(0, 10);
    }
    getDateRange() {
        return this.#dateRange.getValue();
    }
    async getSavedSearches({ skip = 0, take = 999 } = {}) {
        const { data } = await this.#repository.getSavedSearches({ skip, take });
        if (data) {
            this.#savedSearches.setValue(data);
        }
        else {
            //fallback to some default searches resembling Umbraco <= 13
            this.#savedSearches.setValue({
                items: [
                    {
                        name: 'Find all logs where the Level is NOT Verbose and NOT Debug',
                        query: "Not(@Level='Verbose') and Not(@Level='Debug')",
                    },
                    {
                        name: 'Find all logs that has an exception property (Warning, Error & Fatal with Exceptions)',
                        query: 'Has(@Exception)',
                    },
                    {
                        name: "Find all logs that have the property 'Duration'",
                        query: 'Has(Duration)',
                    },
                    {
                        name: "Find all logs that have the property 'Duration' and the duration is greater than 1000ms",
                        query: 'Has(Duration) and Duration > 1000',
                    },
                    {
                        name: "Find all logs that are from the namespace 'Umbraco.Core'",
                        query: "StartsWith(SourceContext, 'Umbraco.Core')",
                    },
                    {
                        name: 'Find all logs that use a specific log message template',
                        query: "@MessageTemplate = '[Timing {TimingId}] {EndMessage} ({TimingDuration}ms)'",
                    },
                ],
                total: 6,
            });
        }
    }
    async saveSearch({ name, query }) {
        const previousSavedSearches = this.#savedSearches.getValue()?.items ?? [];
        try {
            this.#savedSearches.update({ items: [...previousSavedSearches, { name, query }] });
            await this.#repository.saveSearch({ name, query });
        }
        catch {
            this.#savedSearches.update({ items: previousSavedSearches });
        }
    }
    async removeSearch({ name }) {
        const previousSavedSearches = this.#savedSearches.getValue()?.items ?? [];
        try {
            this.#savedSearches.update({ items: previousSavedSearches.filter((search) => search.name !== name) });
            await this.#repository.removeSearch({ name });
        }
        catch {
            this.#savedSearches.update({ items: previousSavedSearches });
        }
    }
    async getLogCount() {
        const { data } = await this.#repository.getLogCount({ ...this.#dateRange.getValue() });
        this.#logCount.setValue(data ?? null);
    }
    async getMessageTemplates(skip, take) {
        const { data } = await this.#repository.getMessageTemplates({ skip, take, ...this.#dateRange.getValue() });
        if (data) {
            this.#messageTemplates.setValue(data);
        }
    }
    async getLogLevels(skip, take) {
        const { data } = await this.#repository.getLogLevels({ skip, take });
        if (data) {
            this.#loggers.setValue(data);
        }
    }
    async validateLogSize() {
        const { error } = await this.#repository.getLogViewerValidateLogsSize({ ...this.#dateRange.getValue() });
        if (error) {
            this.#canShowLogs.setValue(false);
            return;
        }
        this.#canShowLogs.setValue(true);
    }
    setCurrentPage(page) {
        this.currentPage = page;
    }
    setFilterExpression(query) {
        this.#filterExpression.setValue(query);
    }
    setLogLevelsFilter(logLevels) {
        this.#logLevelsFilter.setValue(logLevels);
    }
    #startPolling(interval) {
        this.stopPolling();
        this.#intervalID = setInterval(() => {
            this.currentPage = 1;
            this.getLogs();
        }, interval);
    }
    togglePolling() {
        const isEnabled = !this.#polling.getValue().enabled;
        this.#polling.update({
            enabled: isEnabled,
        });
        if (isEnabled) {
            this.#startPolling(this.#polling.getValue().interval);
            return;
        }
        this.stopPolling();
    }
    setPollingInterval(interval) {
        const wasEnabled = this.#polling.getValue().enabled;
        this.#polling.update({ interval });
        // If polling was already enabled, restart it with the new interval
        // If polling was disabled, enable it and start it with the new interval
        if (wasEnabled) {
            this.#startPolling(interval);
        }
        else {
            this.#polling.update({ enabled: true });
            this.#startPolling(interval);
        }
    }
    toggleSortOrder() {
        const direction = this.#sortingDirection.getValue();
        const newDirection = direction === DirectionModel.ASCENDING ? DirectionModel.DESCENDING : DirectionModel.ASCENDING;
        this.#sortingDirection.setValue(newDirection);
    }
    stopPolling() {
        if (this.#intervalID) {
            clearInterval(this.#intervalID);
            this.#intervalID = null;
        }
    }
}
export { UmbLogViewerWorkspaceContext as api };
