/*
 * Copyright (c) 2024 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.
 * 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 { appTasks } from '@ohos/hvigor-ohos-plugin';
import {
  BaseAnalyzeResult,
  ExtensionContext,
  Logger,
  PluginExtension,
  registerPluginExtension
} from '@hadss/hmrouter-plugin';
import { ClassDeclaration, Expression, PropertyAssignment, SourceFile, SyntaxKind } from 'ts-morph';

interface RouterInfo {
  name: string;
  pageSourceFile: string;
  buildFunction: string;
  customData: Record<string, any>;
}

interface MyExtensionContext extends ExtensionContext {
  customPages?: RouterInfo[];
  routerMap: RouterInfo[];
}

interface MyAnalyzeResult extends BaseAnalyzeResult {
  [key: string]: any;
}

// 示例1: RouterParam注解分析器
export class RouterParamAnalyzer {
  readonly name = 'RouterParamAnalyzer';

  analyze(sourceFile: SourceFile, filePath: string, context: MyExtensionContext): void {
    Logger.debug('', `开始分析RouterParam注解: ${filePath}`);

    // 获取所有ExpressionStatement以获取struct关键字后面的组件名称
    const viewNameArr = sourceFile
      .getChildrenOfKind(SyntaxKind.ExpressionStatement)
      .map((node) => node.getText())
      .filter((text) => text !== 'struct');

    // 解析结构体声明中的RouterParam注解
    sourceFile.getChildrenOfKind(SyntaxKind.MissingDeclaration).forEach((node, index) => {
      node.getChildrenOfKind(SyntaxKind.Decorator).forEach((decorator) => {
        if (decorator.getName() === "RouterParam") {
          // 解析RouterParam注解的参数
          const result: MyAnalyzeResult = {
            name: viewNameArr[index],
            annotation: decorator.getName(),
            sourceFilePath: filePath
          };

          // 解析装饰器参数
          decorator.getArguments().forEach((arg) => {
            const objLiteral = arg.asKind(SyntaxKind.ObjectLiteralExpression);
            if (objLiteral) {
              objLiteral.getProperties().forEach((prop) => {
                if (prop.getKind() === SyntaxKind.PropertyAssignment) {
                  const propertyAssignment = prop as PropertyAssignment;
                  const propertyName = propertyAssignment.getName();
                  const initializer = propertyAssignment.getInitializer();

                  if (initializer) {
                    // 将解析结果添加到result对象
                    result[propertyName] = this.parsePrimitiveValue(initializer);
                  }
                }
              });
            }
          });

          // 如果需要后续保存到路由表中请调用addAnalyzeResults添加分析结果
          // context.addAnalyzeResults(result);

          // 为组件添加模板数据，用于代码生成
          context.addTemplateData(result.name, {
            paramType: result['paramType'] || 'default',
            isCustomParam: true,
            customParams: result['params'] || [],
            sourceFile: filePath
          });

          Logger.debug('', `发现RouterParam注解: ${result.name}`);
        }
      });
    });
  }

  private parsePrimitiveValue(value: Expression): any {
    let propertyValue;
    switch (value.getKind()) {
      case SyntaxKind.StringLiteral:
        propertyValue = value.asKind(SyntaxKind.StringLiteral)?.getLiteralValue();
        break;
      case SyntaxKind.NumericLiteral:
        propertyValue = value.asKind(SyntaxKind.NumericLiteral)?.getLiteralValue();
        break;
      case SyntaxKind.TrueKeyword:
        propertyValue = true;
        break;
      case SyntaxKind.FalseKeyword:
        propertyValue = false;
        break;
      case SyntaxKind.ArrayLiteralExpression:
        propertyValue = value
          .asKind(SyntaxKind.ArrayLiteralExpression)
          ?.getElements()
          .map((item) => {
            if (item.getKind() === SyntaxKind.StringLiteral) {
              return item.asKind(SyntaxKind.StringLiteral)?.getLiteralValue();
            }
            return null;
          })
          .filter(item => item !== null);
        break;
    }
    return propertyValue;
  }
}

// 示例2: CustomPage注解分析器
export class CustomPageAnalyzer {
  readonly name = 'CustomPageAnalyzer';

  analyze(sourceFile: SourceFile, filePath: string, context: MyExtensionContext): void {
    Logger.debug('', `开始分析CustomPage注解: ${filePath}`);

    // 分析使用@CustomPage注解的类
    sourceFile.getClasses().forEach((cls: ClassDeclaration) => {
      cls.getDecorators().forEach(decorator => {
        if (decorator.getName() === 'CustomPage') {
          const className = cls.getName() || '';

          // 创建分析结果
          const result: MyAnalyzeResult = {
            name: className,
            annotation: 'CustomPage',
            sourceFilePath: filePath
          };

          // 解析装饰器参数
          decorator.getArguments().forEach((arg) => {
            const objLiteral = arg.asKind(SyntaxKind.ObjectLiteralExpression);
            if (objLiteral) {
              objLiteral.getProperties().forEach((prop) => {
                if (prop.getKind() === SyntaxKind.PropertyAssignment) {
                  const propertyAssignment = prop as PropertyAssignment;
                  const propertyName = propertyAssignment.getName();
                  const initializer = propertyAssignment.getInitializer();

                  if (initializer && initializer.getKind() === SyntaxKind.StringLiteral) {
                    result[propertyName] = initializer.asKind(SyntaxKind.StringLiteral)?.getLiteralValue();
                  }
                }
              });
            }
          });

          // 添加分析结果
          context.addAnalyzeResults(result);

          // 存储自定义页面路径信息
          const customPages = context.customPages || [];
          customPages.push(result);
          context.customPages = customPages;

          Logger.debug('', `发现CustomPage注解: ${className}, pageUrl: ${result['pageUrl']}`);
        }
      });
    });
  }
}

// 插件扩展类
export class CustomPluginExtension extends PluginExtension<MyExtensionContext> {
  get name(): string {
    return 'CustomPluginExtension';
  }

  // 提供注解分析器
  afterAnnotationAnalysis(sourceFile: SourceFile, filePath: string, context: MyExtensionContext): void {
    const analyzers = [new RouterParamAnalyzer(), new CustomPageAnalyzer()];
    for (const analyzer of analyzers) {
      analyzer.analyze(sourceFile, filePath, context);
    }
  }

  // 代码生成阶段，可以使用RouterParam注解分析结果
  afterCodeGeneration(context: MyExtensionContext): void {
    // 获取所有模板数据
    const templateDataMap = context.getTemplateDataMap();

    // 示例: 输出找到的RouterParam数据
    for (const [componentName, templateData] of templateDataMap.entries()) {
      if (templateData.isCustomParam) {
        Logger.info(
          this.name,
          `组件 ${componentName} 将使用自定义参数类型: ${templateData.paramType}`
        );
        // 实际场景可以在此生成额外的代码
      }
    }
  }

  // 路由表构建阶段，将CustomPage注解分析结果添加到路由表
  afterRouterMapBuilding(context: MyExtensionContext): void {
    // 从私有存储获取CustomPage分析结果
    const customPages = context.customPages || [];

    // 将CustomPage添加到路由表
    for (const page of customPages) {
      const pageUrl = page.customData['pageUrl'];
      if (pageUrl) {
        // 检查路由表中是否已存在该路径
        const existingRoute = context.routerMap.find(route => route.customData.pageUrl === pageUrl);
        if (!existingRoute) {
          // 创建新的路由项并添加到路由表
          context.routerMap.push({
            name: pageUrl,
            buildFunction: page.name,
            pageSourceFile: page.pageSourceFile,
            customData: {
              ...page.customData,
            }
          });

          Logger.info(
            this.name,
            `添加自定义页面到路由表: ${pageUrl} -> ${page.name}`
          );
        }
      }
    }
  }
}

// 注册扩展
registerPluginExtension(new CustomPluginExtension());

export default {
  system: appTasks,
  plugins: []
};
