import type { RsbuildPlugin } from '@rsbuild/core';
import { loadEnv } from '@rsbuild/core';
import fs from 'fs/promises';
import path from 'path';
import { generateExposesFromRoutes } from './generateExposesPlugin';

/**
 * 路由树节点结构，类似 Vue Router 的 RouteRecordRaw
 */
interface RouteInfoNode {
  path: string;
  name?: string;
  component?: string;
  redirect?: string;
  meta?: {
    id?: string;
    title?: string;
    description?: string;
    category?: string;
    icon?: string;
    tags?: string[];
    assets?: {
      js: {
        sync: string[];
        async: string[];
      };
      css: {
        sync: string[];
        async: string[];
      };
    };
  };
  children?: RouteInfoNode[];
}

/**
 * 解析后的路由配置
 */
interface ParsedRoute {
  path: string;
  name?: string;
  componentPath?: string;
  children?: ParsedRoute[];
  meta?: {
    title?: string;
    description?: string;
    category?: string;
    icon?: string;
    tags?: string[];
  };
}

interface ManifestExpose {
  id: string;
  name: string;
  path: string;
  assets: {
    js: {
      sync: string[];
      async: string[];
    };
    css: {
      sync: string[];
      async: string[];
    };
  };
}

interface Manifest {
  id: string;
  name: string;
  exposes: ManifestExpose[];
}

/**
 * 从路由文件中解析路由配置（支持嵌套 children）
 */
async function parseRoutesFromFile(routerPath: string): Promise<ParsedRoute[]> {
  const content = await fs.readFile(routerPath, 'utf-8');

  // 尝试多种路由声明模式
  // 1. export const routes: RouteRecordRaw[] = [...]
  // 2. const routes: RouteRecordRaw[] = [...]
  // 3. const routes: RouteRecordRaw[]\n  =\[...]  (支持换行)
  const routesMatch =
    content.match(
      /export\s+const\s+routes:\s*RouteRecordRaw\[\]\s*=\s*\[(.*)\]/s,
    ) || content.match(/const\s+routes:\s*RouteRecordRaw\[\]\s*=\s*\[(.*)\]/s);

  if (!routesMatch) {
    console.warn(`⚠️  无法从 ${routerPath} 中提取路由配置`);
    return [];
  }

  const routesContent = routesMatch[1];

  // 解析路由列表（递归处理 children）
  return parseRoutesArray(routesContent);
}

/**
 * 解析路由数组
 */
function parseRoutesArray(content: string): ParsedRoute[] {
  const routes: ParsedRoute[] = [];

  let pos = 0;
  while (pos < content.length) {
    // 跳过空白字符和逗号
    while (pos < content.length && /[\s,]/.test(content[pos])) {
      pos++;
    }

    if (pos >= content.length) {
      break;
    }

    // 检查是否是路由对象的开始
    if (content[pos] === '{') {
      const routeObj = extractRouteObject(content, pos);

      if (!routeObj) {
        break;
      }

      // 提取 path 和 name
      const pathMatch = routeObj.match(/path:\s*['"`]([^'"`]+)['"`]/);
      const nameMatch = routeObj.match(/name:\s*['"`]([^'"`]+)['"`]/);

      if (!pathMatch || !nameMatch) {
        pos += routeObj.length;
        continue;
      }

      const routePath = pathMatch[1];
      const routeName = nameMatch[1];

      // 提取 component 路径（支持多种格式）
      // 1. () => import('...')
      // 2. () => Promise.resolve().then(() => jitiImport('...'))
      let componentPath: string | undefined;
      const componentMatch1 = routeObj.match(
        /component:\s*\(\)\s*=>\s*import\(['"`]([^'"`]+)['"`]\)/,
      );
      const componentMatch2 = routeObj.match(
        /jitiImport\(['"`]([^'"`]+\.vue)['"`]\)/,
      );

      if (componentMatch1?.[1]) {
        componentPath = componentMatch1[1];
      } else if (componentMatch2?.[1]) {
        componentPath = componentMatch2[1];
      }

      // 提取 meta
      const meta = extractMeta(routeObj);

      // 提取 children
      const childrenKeywordMatch = routeObj.match(/children:\s*\[/);
      let children: ParsedRoute[] | undefined;
      if (childrenKeywordMatch) {
        const bracketStart =
          childrenKeywordMatch.index + childrenKeywordMatch[0].length - 1;
        const childrenContent = extractBracketContent(routeObj, bracketStart);

        if (childrenContent) {
          children = parseRoutesArray(childrenContent);
        }
      }

      routes.push({
        path: routePath,
        name: routeName,
        componentPath,
        meta,
        children,
      });

      pos += routeObj.length;
    } else {
      pos++;
    }
  }

  return routes;
}

/**
 * 提取完整的路由对象（处理嵌套的大括号）
 */
function extractRouteObject(content: string, startPos: number): string | null {
  let braceCount = 0;
  let inString = false;
  let stringChar = '';
  let i = startPos;

  for (; i < content.length; i++) {
    const char = content[i];

    // 处理字符串
    if (
      (char === '"' || char === "'" || char === '`') &&
      (i === 0 || content[i - 1] !== '\\')
    ) {
      if (!inString) {
        inString = true;
        stringChar = char;
      } else if (char === stringChar) {
        inString = false;
      }
      continue;
    }

    if (inString) continue;

    // 计算大括号
    if (char === '{') {
      braceCount++;
    } else if (char === '}') {
      braceCount--;
      if (braceCount === 0) {
        return content.substring(startPos, i + 1);
      }
    }
  }

  return null;
}

/**
 * 提取方括号内的内容（处理嵌套）
 */
function extractBracketContent(
  content: string,
  startPos: number,
): string | null {
  let bracketCount = 0;
  let inString = false;
  let stringChar = '';
  let i = startPos;

  for (; i < content.length; i++) {
    const char = content[i];

    // 处理字符串
    if (
      (char === '"' || char === "'" || char === '`') &&
      (i === 0 || content[i - 1] !== '\\')
    ) {
      if (!inString) {
        inString = true;
        stringChar = char;
      } else if (char === stringChar) {
        inString = false;
      }
      continue;
    }

    if (inString) continue;

    // 计算方括号
    if (char === '[') {
      bracketCount++;
    } else if (char === ']') {
      bracketCount--;
      if (bracketCount === 0) {
        return content.substring(startPos + 1, i); // 返回 [] 内的内容
      }
    }
  }

  return null;
}

/**
 * 提取 meta 信息
 */
function extractMeta(routeObj: string): ParsedRoute['meta'] {
  const metaMatch = routeObj.match(/meta:\s*\{([\s\S]*?)\}(?=\s*[,}])/);
  if (!metaMatch) {
    return undefined;
  }

  const metaContent = metaMatch[1];

  // 提取 meta 字段
  const titleMatch = metaContent.match(/title:\s*['"`]([^'"`]+)['"`]/);
  const descMatch = metaContent.match(/description:\s*['"`]([^'"`]+)['"`]/);
  const categoryMatch = metaContent.match(/category:\s*['"`]([^'"`]+)['"`]/);
  const iconMatch = metaContent.match(/icon:\s*['"`]([^'"`]+)['"`]/);

  return {
    title: titleMatch?.[1],
    description: descMatch?.[1],
    category: categoryMatch?.[1],
    icon: iconMatch?.[1],
  };
}

/**
 * 从 rsbuild.config.ts 中读取 exposes 配置
 * 新版本：直接调用 generateExposesFromRoutes 函数生成
 * 旧版本：从配置文件中正则提取（兼容性备用）
 */
async function loadExposesConfig(
  configPath: string,
  rootPath: string,
): Promise<Record<string, string>> {
  try {
    // 新方法：直接读取 routes 文件并调用 generateExposesFromRoutes
    const routesPath = path.join(rootPath, 'src/router/routes.ts');
    const indexPath = path.join(rootPath, 'src/router/index.ts');

    let routesContent: string | null = null;

    // 尝试读取 routes.ts
    try {
      routesContent = await fs.readFile(routesPath, 'utf-8');
    } catch {
      // 如果 routes.ts 不存在，尝试读取 index.ts
      try {
        routesContent = await fs.readFile(indexPath, 'utf-8');
      } catch {
        console.warn('⚠️  无法读取路由配置文件');
      }
    }

    if (routesContent) {
      // 从路由文件内容中提取 routes 数组
      const routesMatch =
        routesContent.match(
          /export\s+const\s+routes:\s*RouteRecordRaw\[\]\s*=\s*\[(.*)\]/s,
        ) ||
        routesContent.match(
          /const\s+routes:\s*RouteRecordRaw\[\]\s*=\s*\[(.*)\]/s,
        );

      if (routesMatch) {
        // 注意：这里需要实际的 routes 对象，而不是字符串
        // 我们暂时使用旧的正则方法作为备用
        console.log('✅ 使用 generateExposesFromRoutes 生成 exposes 配置');
      }
    }
  } catch (error) {
    console.warn('⚠️  使用新方法生成 exposes 失败，尝试正则提取:', error);
  }

  // 备用方法：从配置文件中正则提取（兼容旧配置）
  try {
    const content = await fs.readFile(configPath, 'utf-8');

    // 查找 exposes 变量的定义
    const exposesMatch = content.match(
      /const\s*\{\s*exposes\s*\}\s*=\s*generateExposesFromRoutes\([^)]+\)\.exposes/,
    );
    if (exposesMatch) {
      // 找到了 generateExposesFromRoutes 的调用
      // 说明使用的是新的自动生成方式
      // 我们需要手动调用它来生成 exposes
      console.log('✅ 检测到自动生成 exposes 配置');
      return {};
    }

    // 尝试匹配旧的直接配置方式
    const oldExposesMatch = content.match(/exposes:\s*\{([\s\S]*?)\n\s*\}/);
    if (oldExposesMatch) {
      const exposesContent = oldExposesMatch[1];
      const exposes: Record<string, string> = {};

      const exposeRegex = /['"`]([^'"`]+)['"`]\s*:\s*['"`]([^'"`]+)['"`]/g;
      let match;

      while ((match = exposeRegex.exec(exposesContent)) !== null) {
        const [, exposeKey, componentPath] = match;
        exposes[exposeKey] = componentPath;
      }

      return exposes;
    }
  } catch (error) {
    console.error('❌ 读取 exposes 配置失败:', error);
  }

  return {};
}

/**
 * 根据 rsbuild.config.ts 的 exposes 配置，建立组件路径到 expose key 的映射
 * 支持多种路径格式的匹配
 */
function buildExposeMap(exposes: Record<string, string>): Map<string, string> {
  const map = new Map<string, string>();

  for (const [exposeKey, componentPath] of Object.entries(exposes)) {
    // 保存完整路径映射
    map.set(componentPath, exposeKey);

    // 保存文件名映射 (AboutView.vue -> ./Header)
    const fileName = path.basename(componentPath);
    map.set(fileName, exposeKey);

    // 保存不带扩展名的文件名映射 (AboutView -> ./Header)
    const componentName = path.basename(componentPath, '.vue');
    map.set(componentName, exposeKey);

    // 保存相对路径的不同格式
    // ./src/views/HomeView.vue -> ../views/HomeView.vue
    if (componentPath.startsWith('./src/')) {
      const relativePath = componentPath.replace('./src/', '../');
      map.set(relativePath, exposeKey);
      map.set(relativePath.replace(/^\.\./, './src/'), exposeKey);
    }

    // ../views/HomeView.vue -> ./src/views/HomeView.vue
    if (componentPath.startsWith('../')) {
      const srcPath = componentPath.replace('../', './src/');
      map.set(srcPath, exposeKey);
    }
  }

  return map;
}

/**
 * 读取环境变量文件，获取 resourceCode
 * 使用 Rsbuild 的 loadEnv 加载环境变量
 */
async function getResourceCode(
  rootPath: string,
  mode: string,
): Promise<string> {
  try {
    // 使用 Rsbuild 的 loadEnv 加载环境变量
    const env = await loadEnv({ mode, cwd: rootPath });

    // 获取 VUE_APP_RESOURCE_CODE
    const resourceCode =
      env?.parsed?.VUE_APP_RESOURCE_CODE ||
      env?.VUE_APP_RESOURCE_CODE ||
      process.env.VUE_APP_RESOURCE_CODE ||
      '';

    return String(resourceCode).replace(/^['"`]|['"`]$/g, ''); // 移除引号
  } catch (error) {
    console.warn('⚠️  无法读取 resourceCode:', error);
    return process.env.VUE_APP_RESOURCE_CODE || '';
  }
}

/**
 * 生成 routes-info.json 的 Rsbuild 插件
 * 自动从路由配置中读取元数据（支持嵌套 children）
 */
export function generateRoutesInfoPlugin(): RsbuildPlugin {
  return {
    name: 'generate-routes-info',
    setup(api) {
      api.onAfterBuild(async ({ stats }) => {
        if (api.context.mode !== 'production') {
          return;
        }
        try {
          const distPath = api.context.distPath;
          const manifestPath = path.join(distPath, 'mf-manifest.json');
          const rootPath = api.context.rootPath;

          // 获取当前构建模式
          const mode = api.context.mode;

          // 读取 mf-manifest.json
          const manifestContent = await fs.readFile(manifestPath, 'utf-8');
          const manifest: Manifest = JSON.parse(manifestContent);

          // 读取 rsbuild.config.ts 的 exposes 配置
          const configPath = path.join(rootPath, 'rsbuild.config.ts');
          const exposesConfig = await loadExposesConfig(configPath, rootPath);

          // 如果从配置文件读取失败（因为使用了自动生成），则直接生成
          if (Object.keys(exposesConfig).length === 0) {
            console.log('🔄 直接从路由生成 exposes 配置');
            // 需要动态导入 routes 模块
            try {
              const routesModule = await import(
                path.join(rootPath, 'src/router/routes.ts')
              );
              const { exposes: autoExposes } = generateExposesFromRoutes(
                routesModule.routes,
                { onlyLeafNodes: true },
              );
              Object.assign(exposesConfig, autoExposes);
            } catch (error) {
              console.error('❌ 自动生成 exposes 失败:', error);
            }
          }

          // 建立组件路径到 expose key 的映射
          const exposeMap = buildExposeMap(exposesConfig);

          // 读取路由配置（优先从 routes.ts 读取，如果不存在则从 index.ts 读取）
          const routesPath = path.join(rootPath, 'src/router/routes.ts');
          const indexPath = path.join(rootPath, 'src/router/index.ts');

          let parsedRoutes: ParsedRoute[] = [];

          // 先尝试读取 routes.ts
          try {
            await fs.access(routesPath);
            parsedRoutes = await parseRoutesFromFile(routesPath);
            console.log('✅ 从 routes.ts 读取路由配置');
          } catch {
            // 如果 routes.ts 不存在，则尝试从 index.ts 读取
            try {
              parsedRoutes = await parseRoutesFromFile(indexPath);
              console.log('✅ 从 index.ts 读取路由配置');
            } catch (error) {
              console.error('❌ 无法读取路由配置文件:', error);
            }
          }

          // 递归构建路由树
          const pages = buildRouteTree(parsedRoutes, exposeMap, manifest);

          // 读取 resourceCode
          const resourceCode = await getResourceCode(rootPath, mode);

          // 包装成新的格式
          const routesInfo = {
            resourceCode,
            pages,
          };

          // 写入 routes-info.json
          const outputPath = path.join(distPath, 'routes-info.json');
          await fs.writeFile(
            outputPath,
            JSON.stringify(routesInfo, null, 2),
            'utf-8',
          );

          // 统计路由节点数
          const countRoutes = (routes: RouteInfoNode[]): number => {
            let count = 0;
            routes.forEach((route) => {
              count++;
              if (route.children) {
                count += countRoutes(route.children);
              }
            });
            return count;
          };
        } catch (error) {
          console.error('❌ 生成 routes-info.json 失败:', error);
        }
      });
    },
  };
}

/**
 * 递归构建路由树
 */
function buildRouteTree(
  parsedRoutes: ParsedRoute[],
  exposeMap: Map<string, string>,
  manifest: Manifest,
): RouteInfoNode[] {
  return parsedRoutes
    .map((route) => {
      // 如果有 componentPath，查找对应的 expose
      if (route.componentPath) {
        const componentPath = route.componentPath;

        // 尝试多种方式查找 expose
        const exposeKey =
          exposeMap.get(componentPath) ||
          exposeMap.get(path.basename(componentPath)) ||
          exposeMap.get(path.basename(componentPath, '.vue')) ||
          exposeMap.get(componentPath.replace('../views/', './src/views/'));

        if (exposeKey) {
          // 找到了对应的 expose
          const expose = manifest.exposes.find((e) => e.path === exposeKey);
          if (!expose) {
            console.warn(`⚠️  manifest 中未找到 expose: ${exposeKey}`);
            return null;
          }

          const routeNode: RouteInfoNode = {
            path: route.path,
            name: route.name,
            component: exposeKey,
            meta: {
              id: expose.id,
              title: route.meta?.title,
              description: route.meta?.description,
              category: route.meta?.category,
              icon: route.meta?.icon,
            },
          };

          // 递归处理 children
          if (route.children && route.children.length > 0) {
            routeNode.children = buildRouteTree(
              route.children,
              exposeMap,
              manifest,
            );
          }

          return routeNode;
        } else {
          // 没有找到对应的 expose（可能是因为 onlyLeafNodes 模式）
          // 仍然保留路由信息，但不设置 component 和 id
          console.log(
            `ℹ️  路由 ${route.path} (${route.componentPath}) 未在 exposes 中找到（可能有子路由）`,
          );

          const routeNode: RouteInfoNode = {
            path: route.path,
            name: route.name,
            meta: {
              title: route.meta?.title,
              description: route.meta?.description,
              category: route.meta?.category,
              icon: route.meta?.icon,
              tags: route.meta?.tags,
            },
          };

          // 递归处理 children
          if (route.children && route.children.length > 0) {
            routeNode.children = buildRouteTree(
              route.children,
              exposeMap,
              manifest,
            );
          }

          return routeNode;
        }
      } else {
        // 没有 component 的路由（如重定向、布局等）
        const routeNode: RouteInfoNode = {
          path: route.path,
          name: route.name,
          meta: {
            title: route.meta?.title,
            description: route.meta?.description,
            category: route.meta?.category,
            icon: route.meta?.icon,
            tags: route.meta?.tags,
          },
        };

        // 递归处理 children
        if (route.children && route.children.length > 0) {
          routeNode.children = buildRouteTree(
            route.children,
            exposeMap,
            manifest,
          );
        }

        return routeNode;
      }
    })
    .filter((route): route is RouteInfoNode => route !== null);
}
