import { mkdir, writeFile } from "node:fs/promises";
import { existsSync } from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";

const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
const args = process.argv.slice(2);
const featureName = args.find((arg) => !arg.startsWith("--"));

if (!featureName) {
  console.error("Usage: pnpm scaffold:feature <feature-name> --label=模块名称 --path=/path --menu-code=menu-code --permission=module:view");
  process.exit(1);
}

const options = Object.fromEntries(
  args
    .filter((arg) => arg.startsWith("--"))
    .map((arg) => {
      const [key, ...valueParts] = arg.slice(2).split("=");
      return [key, valueParts.join("=")];
    })
);

const kebabName = toKebabCase(featureName);
const camelName = toCamelCase(kebabName);
const pascalName = toPascalCase(kebabName);
const routePath = options.path || `/${kebabName}`;
const label = options.label || pascalName;
const menuCode = options["menu-code"] || kebabName;
const permission = options.permission || `${kebabName}:view`;
const featureDir = path.join(rootDir, "src/features", kebabName);

const files = new Map([
  [
    "api.ts",
    `import { apiRequest } from "@/shared/api/request";

export function list${pascalName}(query?: Record<string, string | number>) {
  return apiRequest("${routePath}", { query });
}
`
  ],
  [
    "routes.js",
    `export const ${camelName}Routes = [
  {
    label: ${JSON.stringify(label)},
    loader: () => import("./pages/${pascalName}Page.jsx").then((module) => module.${pascalName}Page),
    menuCode: ${JSON.stringify(menuCode)},
    pageKey: ${JSON.stringify(kebabName)},
    path: ${JSON.stringify(routePath)},
    permission: ${JSON.stringify(permission)}
  }
];
`
  ],
  [
    "permissions.js",
    `import { useAuth } from "@/app/auth/AuthProvider.jsx";

export function use${pascalName}Abilities() {
  const { can } = useAuth();

  return {
    canView: can(${JSON.stringify(permission)})
  };
}
`
  ],
  [
    `hooks/use${pascalName}Page.js`,
    `import { useCallback } from "react";
import { useAdminQuery } from "@/shared/hooks/useAdminQuery.js";
import { list${pascalName} } from "@/features/${kebabName}/api";
import { use${pascalName}Abilities } from "@/features/${kebabName}/permissions.js";

const emptyData = { items: [], total: 0, page: 1, pageSize: 10 };

export function use${pascalName}Page() {
  const abilities = use${pascalName}Abilities();
  const queryFn = useCallback(() => list${pascalName}({ page: 1, page_size: 10 }), []);
  const { data, error, loading, reload } = useAdminQuery(queryFn, {
    errorMessage: "加载失败",
    initialData: emptyData,
    queryKey: [${JSON.stringify(kebabName)}]
  });

  return { abilities, data, error, loading, reload };
}
`
  ],
  [
    `pages/${pascalName}Page.jsx`,
    `import { DataState } from "@/shared/ui/DataState.jsx";
import { use${pascalName}Page } from "@/features/${kebabName}/hooks/use${pascalName}Page.js";
import styles from "@/features/${kebabName}/${kebabName}.module.css";

export function ${pascalName}Page() {
  const page = use${pascalName}Page();

  return (
    <DataState error={page.error} loading={page.loading} onRetry={page.reload}>
      <section className={styles.root} />
    </DataState>
  );
}
`
  ],
  [
    `${kebabName}.module.css`,
    `.root {
  min-height: 100%;
}
`
  ],
  ["components/.gitkeep", ""]
]);

await mkdir(featureDir, { recursive: true });

for (const [relativePath, content] of files) {
  const absolutePath = path.join(featureDir, relativePath);
  await mkdir(path.dirname(absolutePath), { recursive: true });
  if (existsSync(absolutePath)) {
    console.log(`Skipped existing ${path.relative(rootDir, absolutePath)}`);
    continue;
  }
  await writeFile(absolutePath, content);
  console.log(`Created ${path.relative(rootDir, absolutePath)}`);
}

function toKebabCase(value) {
  return value
    .replace(/([a-z0-9])([A-Z])/g, "$1-$2")
    .replace(/[^a-zA-Z0-9]+/g, "-")
    .replace(/^-|-$/g, "")
    .toLowerCase();
}

function toCamelCase(value) {
  return value.replace(/-([a-z0-9])/g, (_, letter) => letter.toUpperCase());
}

function toPascalCase(value) {
  const camel = toCamelCase(value);
  return camel.charAt(0).toUpperCase() + camel.slice(1);
}
