// *****************************************************************************
// Copyright (C) 2024 EclipseSource GmbH.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
import {
    ChatMode, ChatRequestModel, ChatService, ChatSession,
    MutableChatModel, MutableChatRequestModel
} from '@theia/ai-chat/lib/common';
import { TaskContextStorageService } from '@theia/ai-chat/lib/browser/task-context-service';
import { LanguageModelRequirement } from '@theia/ai-core';
import { inject, injectable } from '@theia/core/shared/inversify';
import { architectSystemVariants, ARCHITECT_PLANNING_PROMPT_ID, ARCHITECT_SIMPLE_PROMPT_ID, ARCHITECT_PLANNING_NEXT_PROMPT_ID } from './architect-prompt-template';
import { nls } from '@theia/core';
import { FrontendApplicationConfigProvider } from '@theia/core/lib/browser/frontend-application-config-provider';
import { MarkdownStringImpl } from '@theia/core/lib/common/markdown-rendering';
import { AI_EXECUTE_PLAN_WITH_CODER } from '../common/summarize-session-commands';
import { AbstractModeAwareChatAgent } from './mode-aware-chat-agent';
import { ArchitectAgentId } from '../common/agent-ids';

export { ArchitectAgentId };

@injectable()
export class ArchitectAgent extends AbstractModeAwareChatAgent {
    @inject(ChatService) protected readonly chatService: ChatService;
    @inject(TaskContextStorageService) protected readonly taskContextStorageService: TaskContextStorageService;

    name = ArchitectAgentId;
    id = ArchitectAgentId;
    languageModelRequirements: LanguageModelRequirement[] = [{
        purpose: 'chat',
        identifier: 'default/code',
    }];
    protected defaultLanguageModelPurpose: string = 'chat';
    override iconClass: string = 'codicon codicon-map';

    override description = nls.localize('theia/ai/workspace/workspaceAgent/description',
        'An AI assistant integrated into {0}, designed to assist software developers. This agent can access the users workspace, it can get a list of all available files' +
        ' and folders and retrieve their content. It cannot modify files. It can therefore answer questions about the current project, project files and source code in the' +
        ' workspace, such as how to build the project, where to put source code, where to find specific code or configurations, etc.',
        FrontendApplicationConfigProvider.get().applicationName);

    protected readonly modeDefinitions: Omit<ChatMode, 'isDefault'>[] = [
        {
            id: ARCHITECT_PLANNING_PROMPT_ID,
            name: nls.localizeByDefault('Plan Mode')
        },
        {
            id: ARCHITECT_SIMPLE_PROMPT_ID,
            name: nls.localize('theia/ai/ide/architectAgent/mode/simple', 'Simple Mode')
        },
        {
            id: ARCHITECT_PLANNING_NEXT_PROMPT_ID,
            name: nls.localize('theia/ai/ide/architectAgent/mode/planNext', 'Plan Mode (Next)')
        },
    ];

    override prompts = [architectSystemVariants];
    protected override systemPromptId: string | undefined = architectSystemVariants.id;

    override async invoke(request: MutableChatRequestModel): Promise<void> {
        await super.invoke(request);
        this.suggest(request);
    }

    async suggest(context: ChatSession | ChatRequestModel): Promise<void> {
        const model = ChatRequestModel.is(context) ? context.session : context.model;
        const session = this.chatService.getSessions().find(candidate => candidate.model.id === model.id);
        if (!(model instanceof MutableChatModel) || !session) { return; }
        if (!model.isEmpty()) {
            const taskContexts = this.taskContextStorageService.getAll().filter(s => s.sessionId === session.id);
            if (taskContexts.length > 0) {
                const suggestions = taskContexts.map(tc =>
                    new MarkdownStringImpl(`[${nls.localize('theia/ai/ide/architectAgent/suggestion/executePlanWithCoder',
                        'Execute "{0}" with Coder', tc.label)}](command:${AI_EXECUTE_PLAN_WITH_CODER.id}?${encodeURIComponent(JSON.stringify(tc.id))}).`)
                );
                model.setSuggestions(suggestions);
            }
        }
    }
}
