import { Request, Response, NextFunction, RequestHandler } from "express";
import { ToolPrompt } from "../models/ToolPrompt";
import { ToolPage } from "../models/ToolPage";
import { Language } from "../models/Language";
import { QueryBuilder } from "objection";
export class ToolPromptsController {
  private sendError(res: Response, status: number, message: string): void {
    res.status(status).json({ message });
  }

  private sendSuccess(res: Response, message: string, data?: any): void {
    res.status(200).json({ success: true, message, data });
  }

  show: RequestHandler = async (
    req: Request,
    res: Response,
    next: NextFunction
  ): Promise<void> => {
    try {
      const ToolPrompts = await ToolPrompt.query()
        // The list view does not display the full prompt text. Omitting it keeps
        // this endpoint lightweight; the single-prompt endpoint still returns it
        // when someone opens a prompt for editing.
        .select("id", "page_id", "prompt_variation", "lang")
        .withGraphFetched("[language, page]")
        .modifyGraph("language", (builder: QueryBuilder<Language>) => {
          builder.select("id", "name");
        })
        .modifyGraph("page", (builder: QueryBuilder<ToolPage>) => {
          builder.select("id", "tool_name");
        });

      const result = ToolPrompts.map((prompt: ToolPrompt) => ({
        id: prompt.id,
        page_id: prompt.page_id,
        prompt_variation: prompt.prompt_variation,
        lang: prompt.lang,
        language: prompt.language?.name ?? null,
        tool_page_name: prompt.page?.tool_name ?? null,
        tool_page_id: prompt.page?.id ?? null,
      }));
      this.sendSuccess(res, "Tool prompts fetched successfully", result);
    } catch (error) {
      console.error("Error fetching tool prompts:", error);
      next(error);
    }
  };
  getTools: RequestHandler = async (
    req: Request,
    res: Response,
    next: NextFunction
  ): Promise<void> => {
    try {
      const ToolPages = await ToolPage.query()
        .select("id", "page_slug")
        .where("is_active", true);

      // Map results into a clean array
      const result = ToolPages.map((tool: any) => ({
        tool_page_id: tool.id,
        tool_page_name: tool.page_slug,
      }));

      this.sendSuccess(res, "Tool pages fetched successfully", result);
    } catch (error) {
      console.error("Error fetching tool pages:", error);
      next(error);
    }
  };

  add: RequestHandler = async (
    req: Request,
    res: Response,
    next: NextFunction
  ): Promise<void> => {
    try {
      const { tool_page_name, prompt_variation, prompt_context, lang } =
        req.body;

      if (!tool_page_name || !prompt_variation || !prompt_context || !lang) {
        return this.sendError(res, 400, "Missing required fields");
      }

      const language = await Language.query()
        .findOne({ lang_code: lang })
        .select("id");
      if (!language) {
        return this.sendError(res, 400, "Invalid language code");
      }

      const toolPage = await ToolPage.query()
        .findById(tool_page_name)
        .select("id");
      if (!toolPage) {
        return this.sendError(res, 400, "Invalid tool page ID");
      }

      const newPrompt = await ToolPrompt.query().insert({
        page_id: tool_page_name,
        prompt_variation,
        prompt_context,
        lang: language.id,
      });

      const createdPrompt = await ToolPrompt.query()
        .findById(newPrompt.id)
        .withGraphFetched("[language, page]")
        .modifyGraph("language", (builder: QueryBuilder<Language>) => {
          builder.select("id", "name");
        })
        .modifyGraph("page", (builder: QueryBuilder<ToolPage>) => {
          builder.select("id", "tool_name");
        });

      const result = {
        id: createdPrompt.id,
        page_id: createdPrompt.tool_page_name,
        prompt_variation: createdPrompt.prompt_variation,
        prompt_context: createdPrompt.prompt_context,
        lang: createdPrompt.lang,
      };

      this.sendSuccess(res, "Tool prompt created successfully", result);
    } catch (error) {
      console.error("Error creating tool prompt:", error);
      next(error);
    }
  };

  get: RequestHandler = async (
    req: Request,
    res: Response,
    next: NextFunction
  ): Promise<void> => {
    try {
      const { id } = req.params;

      const prompt = await ToolPrompt.query()
        .findById(id)
        .withGraphFetched("language")
        .modifyGraph("language", (builder: QueryBuilder<Language>) => {
          builder.select("id", "name", "lang_code"); // Removed duplicate "id"
        })
        .modifyGraph("page", (builder: QueryBuilder<ToolPage>) => {
          builder.select("id", "tool_name");
        });

      if (!prompt) {
        return this.sendError(res, 404, "Tool prompt not found");
      }

      const result = {
        id: prompt.id,
        page_id: prompt.page_id,
        prompt_variation: prompt.prompt_variation,
        prompt_context: prompt.prompt_context,
        lang: prompt.lang,
        language: prompt.language?.name ?? null,
        lang_code: prompt.language?.lang_code ?? null,
      };

      this.sendSuccess(res, "Tool prompt fetched successfully", result);
    } catch (error) {
      console.error("Error fetching tool prompt:", error);
      next(error);
    }
  };

  edit: RequestHandler = async (
    req: Request,
    res: Response,
    next: NextFunction
  ): Promise<void> => {
    try {
      const { id } = req.params;
      const { tool_page_name, prompt_variation, prompt_context, lang } =
        req.body;

      const existingPrompt = await ToolPrompt.query().findById(id);
      if (!existingPrompt) {
        return this.sendError(res, 404, "Tool prompt not found");
      }

      let languageId = existingPrompt.lang;
      if (lang) {
        const language = await Language.query()
          .findOne({ lang_code: lang })
          .select("id");
        if (!language) {
          return this.sendError(res, 400, "Invalid language code");
        }
        languageId = language.id;
      }

      let toolPageId = existingPrompt.tool_page_name;
      if (tool_page_name) {
        const toolPage = await ToolPage.query()
          .findById(tool_page_name)
          .select("id");
        if (!toolPage) {
          return this.sendError(res, 400, "Invalid tool page ID");
        }
        toolPageId = tool_page_name;
      }

      const updatedPrompt = await ToolPrompt.query().patchAndFetchById(id, {
        page_id: toolPageId,
        prompt_variation: prompt_variation ?? existingPrompt.prompt_variation,
        prompt_context: prompt_context ?? existingPrompt.prompt_context,
        lang: languageId,
      });

      const resultPrompt = await ToolPrompt.query()
        .findById(updatedPrompt.id)
        .withGraphFetched("[language, page]")
        .modifyGraph("language", (builder: QueryBuilder<Language>) => {
          builder.select("id", "name");
        })
        .modifyGraph("page", (builder: QueryBuilder<ToolPage>) => {
          builder.select("id", "tool_name");
        });

      const result = {
        id: resultPrompt.id,
        page_id: resultPrompt.tool_page_name,
        prompt_variation: resultPrompt.prompt_variation,
        prompt_context: resultPrompt.prompt_context,
        lang: resultPrompt.lang,
      };

      this.sendSuccess(res, "Tool prompt updated successfully", result);
    } catch (error) {
      console.error("Error updating tool prompt:", error);
      next(error);
    }
  };

  delete: RequestHandler = async (
    req: Request,
    res: Response,
    next: NextFunction
  ): Promise<void> => {
    try {
      const { id } = req.params;

      const deletedCount = await ToolPrompt.query().deleteById(id);

      if (deletedCount === 0) {
        return this.sendError(res, 404, "Tool prompt not found");
      }

      this.sendSuccess(res, "Tool prompt deleted successfully");
    } catch (error) {
      console.error("Error deleting tool prompt:", error);
      next(error);
    }
  };
}
