import {
  RULESYNC_MCP_FILE_NAME,
  RULESYNC_MCP_SCHEMA_URL,
  RULESYNC_RELATIVE_DIR_PATH,
} from "../../constants/rulesync-paths.js";
import { AiFileFromFileParams, AiFileParams } from "../../types/ai-file.js";
import { ToolFile } from "../../types/tool-file.js";
import type { Logger } from "../../utils/logger.js";
import { RulesyncMcp } from "./rulesync-mcp.js";

export type ToolMcpParams = AiFileParams;

export type ToolMcpFromRulesyncMcpParams = Omit<
  AiFileParams,
  "fileContent" | "relativeFilePath" | "relativeDirPath"
> & {
  rulesyncMcp: RulesyncMcp;
};

export type ToolMcpFromFileParams = Pick<
  AiFileFromFileParams,
  "outputRoot" | "validate" | "global"
> & {
  logger?: Logger;
};

export type ToolMcpForDeletionParams = {
  outputRoot?: string;
  relativeDirPath: string;
  relativeFilePath: string;
  global?: boolean;
};

export type ToolMcpSettablePaths = {
  relativeDirPath: string;
  relativeFilePath: string;
};

export abstract class ToolMcp extends ToolFile {
  constructor({ ...rest }: ToolMcpParams) {
    super({
      ...rest,
      validate: true, // ToolMcp runs subclass validation below when requested
    });

    // Validate after setting patterns, if validation was requested
    if (rest.validate) {
      const result = this.validate();
      if (!result.success) {
        throw result.error;
      }
    }
  }

  static getSettablePaths(): ToolMcpSettablePaths {
    throw new Error("Please implement this method in the subclass.");
  }

  static getToolTargetsGlobal(): ToolMcpSettablePaths {
    throw new Error("Please implement this method in the subclass.");
  }

  abstract toRulesyncMcp(): RulesyncMcp;

  protected toRulesyncMcpDefault({
    fileContent = undefined,
  }: {
    fileContent?: string;
  } = {}): RulesyncMcp {
    const content = fileContent ?? this.fileContent;
    const { $schema: _, ...json } = JSON.parse(content);
    const withSchema = {
      $schema: RULESYNC_MCP_SCHEMA_URL,
      ...json,
    };
    return new RulesyncMcp({
      outputRoot: this.outputRoot,
      relativeDirPath: RULESYNC_RELATIVE_DIR_PATH,
      relativeFilePath: RULESYNC_MCP_FILE_NAME,
      fileContent: JSON.stringify(withSchema, null, 2),
    });
  }

  static async fromFile(_params: ToolMcpFromFileParams): Promise<ToolMcp> {
    throw new Error("Please implement this method in the subclass.");
  }

  /**
   * Create a minimal instance for deletion purposes.
   * This method does not read or parse file content, making it safe to use
   * even when files have old/incompatible formats.
   */
  static forDeletion(_params: ToolMcpForDeletionParams): ToolMcp {
    throw new Error("Please implement this method in the subclass.");
  }

  static fromRulesyncMcp(_params: ToolMcpFromRulesyncMcpParams): ToolMcp | Promise<ToolMcp> {
    throw new Error("Please implement this method in the subclass.");
  }
}
