/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License at a You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import * as arkts from '@koalaui/libarkts';
import { SuggestionOptions } from './log-collector';

export function findFirstStmtPosition(program: arkts.Program): arkts.SourcePosition {
    const scriptFile = program.ast;
    if (!arkts.isETSModule(scriptFile) || !scriptFile.statements || scriptFile.statements.length === 0) {
        return arkts.createSourcePosition(0, 0);
    }
    return scriptFile.statements[0].endPosition;
}

export interface ImportInfo {
    importedNames: Set<string>;
    arkUIImportNode?: arkts.ImportDeclaration;
    lastImportNode?: arkts.ImportDeclaration;
}

export function collectFileImports(scriptFile: arkts.ETSModule): ImportInfo {
    const importedNames = new Set<string>();
    let arkUIImportNode: arkts.ImportDeclaration | undefined;
    let lastImportNode: arkts.ImportDeclaration | undefined;

    if (!arkts.isETSModule(scriptFile) || !scriptFile.statements) {
        return { importedNames, arkUIImportNode, lastImportNode };
    }
    for (const stmt of scriptFile.statements) {
        if (!arkts.isImportDeclaration(stmt)) {
            continue;
        }
        lastImportNode = stmt;
        const moduleName = getImportModuleName(stmt);
        if (!moduleName) {
            continue;
        }
        collectImportedNames(stmt.specifiers, importedNames);
        if (moduleName === '@kit.ArkUI' && !arkUIImportNode) {
            arkUIImportNode = stmt;
        }
    }
    return { importedNames, arkUIImportNode, lastImportNode };
}

function getImportModuleName(importNode: arkts.ImportDeclaration): string | undefined {
    if (!importNode.source || !arkts.isStringLiteral(importNode.source)) {
        return undefined;
    }
    return importNode.source.str;
}

function collectImportedNames(
    specifiers: readonly arkts.AstNode[] | undefined,
    importedNames: Set<string>
): void {
    if (!specifiers) {
        return;
    }
    for (const spec of specifiers) {
        if (!arkts.isImportSpecifier(spec) || !spec.imported) {
            continue;
        }
        importedNames.add(getIdentifierName(spec.imported));
    }
}

function getIdentifierName(node: arkts.AstNode): string {
    if (arkts.isIdentifier(node)) {
        return node.name;
    }
    if (arkts.isStringLiteral(node)) {
        return node.str;
    }
    return '';
}

export function collectFileImportsByProgram(program: arkts.Program): ImportInfo {
    const scriptFile = program.ast;
    if (!arkts.isETSModule(scriptFile)) {
        return { importedNames: new Set<string>(), arkUIImportNode: undefined, lastImportNode: undefined };
    }
    return collectFileImports(scriptFile);
}

export function createImportFixesByProgram(
    importsInfo: ImportInfo | undefined,
    program: arkts.Program | undefined,
    importNames: string[],
    title: string
): SuggestionOptions[] {
    if (!program) {
        return [];
    }
    const missingImports = importsInfo ? importNames.filter(name => !importsInfo.importedNames.has(name)) : importNames;
    if (missingImports.length === 0) {
        return [];
    }
    const fixes: SuggestionOptions[] = [];
    if (importsInfo?.arkUIImportNode) {
        const specifiers = importsInfo.arkUIImportNode.specifiers;
        if (specifiers && specifiers.length > 0) {
            const lastSpecifier = specifiers[specifiers.length - 1];
            const insertPos = lastSpecifier.endPosition;
            fixes.push({
                code: ', ' + missingImports.join(', '),
                range: [insertPos, insertPos],
                title: title,
            });
        }
    } else if (importsInfo?.lastImportNode) {
        const importCode = `\nimport { ${missingImports.join(', ')} } from '@kit.ArkUI';`;
        const insertPos = importsInfo.lastImportNode.endPosition;
        fixes.push({
            code: importCode,
            range: [insertPos, insertPos],
            title: title,
        });
    } else {
        const importCode = `import { ${missingImports.join(', ')} } from '@kit.ArkUI';\n`;
        const firstStmtPos = findFirstStmtPosition(program);
        fixes.push({
            code: importCode,
            range: [firstStmtPos, firstStmtPos],
            title: title,
        });
    }
    return fixes;
}