// import fs from "fs";
// import path from "path";
// import yaml from "js-yaml";

// type JSONSchema = {
//     type?: string;
//     properties?: Record<string, JSONSchema>;
//     items?: JSONSchema;
//     required?: string[];
//     enum?: string[];
//     description?: string;
//     [key: string]: any;
// };

// function schemaToSpectralRules(schema: JSONSchema, basePath = "$"): Record<string, any> {
//     const rules: Record<string, any> = {};

//     if (schema.type === "object" && schema.properties) {
//         for (const [prop, propSchema] of Object.entries<JSONSchema>(schema.properties)) {
//             const ruleName = `valid-${prop.replace(/[^a-zA-Z0-9]/g, "-")}`;
//             rules[ruleName] = {
//                 description: propSchema.description || `Validate ${prop} at ${basePath}.${prop}`,
//                 given: `${basePath}.${prop}`,
//                 severity: "error",
//                 then: {
//                     function: "schema",
//                     functionOptions: {
//                         schema: propSchema,
//                     },
//                 },
//             };

//             if (propSchema.type === "object" || propSchema.type === "array") {
//                 Object.assign(rules, schemaToSpectralRules(propSchema, `${basePath}.${prop}`));
//             }
//         }
//     }

//     if (schema.type === "array" && schema.items) {
//         Object.assign(rules, schemaToSpectralRules(schema.items, `${basePath}[*]`));
//     }

//     return rules;
// }

// function generateRuleset(schemaPath: string) {
//     const schema = JSON.parse(fs.readFileSync(schemaPath, "utf8")) as JSONSchema;

//     const rules = schemaToSpectralRules(schema);

//     const ruleset = {
//         extends: ["./global-assets-rule.spectral.yaml"],
//         rules,
//     };

//     const outFile = path.join(
//         path.dirname(schemaPath),
//         path.basename(schemaPath, path.extname(schemaPath)) + "-spectral.ruleset.yaml"
//     );

//     fs.writeFileSync(outFile, yaml.dump(ruleset, { noRefs: true }));
//     console.log(`Spectral ruleset generated: ${outFile}`);
// }

// if (process.argv.length < 3) {
//     console.error("Usage: ts-node generate-ruleset.ts <schema-file>");
//     process.exit(1);
// }

// generateRuleset(process.argv[2]);

// generator.ts
import fs from "fs";
import path from "path";
import yaml from "js-yaml";

export interface GenerationOptions {
  specPath: string;
  outputRoot: string;
}

type ValidationSpec = Record<string, any>;

/**
 * Recursively extract x-validation rules from schema
 */
function extractValidations(schema: any, parentPath: string[] = []): Record<string, ValidationSpec> {
  let validations: Record<string, ValidationSpec> = {};

  if (schema && typeof schema === "object") {
    // If node has x-validation
    if (schema["x-validation"]) {
      validations[parentPath.join(".") || "root"] = schema["x-validation"];
    }

    // Check properties recursively
    if (schema.properties) {
      for (const [prop, propSchema] of Object.entries<any>(schema.properties)) {
        const childPath = [...parentPath, prop];
        validations = {
          ...validations,
          ...extractValidations(propSchema, childPath),
        };
      }
    }
  }

  return validations;
}

/**
 * Generate spectral ruleset YAML
 */
function generateRuleset(validations: Record<string, ValidationSpec>, functionsDir: string) {
  const rules: Record<string, any> = {};
  const functions: string[] = [];

  for (const [pathKey, validationObj] of Object.entries(validations)) {
    for (const [fnName, fnConfig] of Object.entries<any>(validationObj)) {
      const ruleName = `${fnName}-${pathKey.replace(/\./g, "_")}`;

      // Reference the function file
      const fnFile = `./functions/${fnName}.ts`;
      if (!functions.includes(fnFile)) {
        functions.push(fnFile);
      }

      rules[ruleName] = {
        description: `Validation for ${pathKey} using ${fnName}`,
        message: `Field ${pathKey} failed validation: ${fnName}`,
        given: `$..${pathKey.split(".").join(".properties.")}`,
        then: {
          function: fnName,
          functionOptions: fnConfig,
        },
      };
    }
  }

  return {
    extends: ["spectral:oas", "spectral:asyncapi", "spectral:json-schema-draft7"],
    functions: functions,
    rules: rules,
  };
}

/**
 * Generate a stub function file for each validation
 */
function generateFunctionFiles(validations: Record<string, ValidationSpec>, functionsDir: string) {
  if (!fs.existsSync(functionsDir)) {
    fs.mkdirSync(functionsDir, { recursive: true });
  }

  for (const validationObj of Object.values(validations)) {
    for (const [fnName] of Object.entries<any>(validationObj)) {
      const fnPath = path.join(functionsDir, `${fnName}.ts`);
      if (!fs.existsSync(fnPath)) {
        const fnContent = `
// ${fnName}.ts
import { IFunction, IFunctionResult } from "@stoplight/spectral-core";

export const ${fnName}: IFunction = (targetVal, opts, ctx) => {
  const results: IFunctionResult[] = [];
  // TODO: Implement validation logic
  // Example: regex pattern check
  if (opts?.pattern) {
    const regex = new RegExp(opts.pattern);
    if (typeof targetVal === "string" && !regex.test(targetVal)) {
      results.push({
        message: \`Value "\${targetVal}" does not match pattern \${opts.pattern}\`,
      });
    }
  }
  return results;
};
        `.trimStart();

        fs.writeFileSync(fnPath, fnContent, "utf-8");
        console.log(`Created function file: ${fnPath}`);
      }
    }
  }
}

/**
 * Main generator
 */
export async function generateTypes({ specPath, outputRoot }: GenerationOptions) {
  const content = fs.readFileSync(specPath, "utf-8");
  const schema = specPath.endsWith(".yaml") || specPath.endsWith(".yml") ? yaml.load(content) : JSON.parse(content);

  const validations = extractValidations(schema);
  const functionsDir = path.join(outputRoot, "functions");

  // Generate ruleset
  const ruleset = generateRuleset(validations, functionsDir);
  const rulesetFile = path.join(
    outputRoot,
    `${path.basename(specPath, path.extname(specPath))}-spectral.ruleset.yaml`
  );
  fs.writeFileSync(rulesetFile, yaml.dump(ruleset), "utf-8");
  console.log(`Generated ruleset: ${rulesetFile}`);

  // Generate functions
  generateFunctionFiles(validations, functionsDir);
}