import { Effect, Schema } from "effect"
import * as Tool from "../core/tool"
import { WarpGrepClient } from "@morphllm/morphsdk/tools/warp-grep/client" 
import { Telemetry } from "@saeeol/telemetry" 
import { Instance } from "../../project/instance"
import { Bus } from "../../bus"
import { TuiEvent } from "../../cli/cmd/tui/event"
import DESCRIPTION from "./warpgrep.txt"

const SAEEOL_WARPGREP_PROXY_URL = "https://api.saeeol.ai/api/gateway"

const Parameters = Schema.Struct({
  query: Schema.String.annotate({
    description: "Search query describing what code you are looking for. Be specific and descriptive for best results.", 
  }),
})

export const CodebaseSearchTool = Tool.define(
  "codebase_search",
  Effect.gen(function* () {
    return {
      description: DESCRIPTION,
      parameters: Parameters,
      execute: (params: Schema.Schema.Type<typeof Parameters>, ctx: Tool.Context) =>
        Effect.gen(function* () {
          yield* ctx.ask({
            permission: "codebase_search",
            patterns: [params.query],
            always: ["*"],
            metadata: { query: params.query },
          })
          Telemetry.trackToolUsed("codebase_search", ctx.sessionID) 

          const apiKey = process.env["MORPH_API_KEY"]

          const client = new WarpGrepClient({
            morphApiKey: apiKey ?? "saeeol-free",
            ...(apiKey ? {} : { morphApiUrl: SAEEOL_WARPGREP_PROXY_URL }),
            timeout: 60_000,
          })

          const result = yield* Effect.promise(() =>
            client.execute({
              searchTerm: params.query,
              repoRoot: Instance.directory,
            }),
          )

          if (!result.success || !result.contexts?.length) {
            const isAuthOrRateLimit =
              result.error && /401|402|429|rate.limit|free.period|unauthorized/i.test(result.error) 
            const apiKeyMsg =
              "Codebase search unavailable: free period ended. Set MORPH_API_KEY to continue. Get your key at https://www.morphllm.com/"
            if (isAuthOrRateLimit) {
              yield* Effect.promise(() =>
                Bus.publish(TuiEvent.ToastShow, {
                  title: "Codebase Search Unavailable",
                  message: "Free period has ended. Set MORPH_API_KEY to continue. Get your key at morphllm.com",
                  variant: "error",
                  duration: 10000,
                }).catch(() => {}),
              )
            }
            return {
              title: `Codebase Search: ${params.query}`,
              output: isAuthOrRateLimit ? apiKeyMsg : (result.error ?? "No relevant code found."),
              metadata: { count: 0 },
            }
          }

          const MAX_OUTPUT_CHARS = 45_000
          const fullOutput = result.contexts.map((c) => `### ${c.file}\n\`\`\`\n${c.content}\n\`\`\``).join("\n\n") 

          let output: string
          if (fullOutput.length > MAX_OUTPUT_CHARS) {
            const summary = result.contexts
              .map((c) => {
                const lineInfo = !c.lines
                  ? ""
                  : c.lines === "*"
                    ? " (full file)"
                    : ` (lines ${c.lines.map((r) => r.join("-")).join(", ")})`
                return `- ${c.file}${lineInfo}`
              })
              .join("\n")
            output = `Results too large to show inline. Showing file paths and line ranges. Use Read tool to view specific files.\n\n${summary}`
          } else {
            output = fullOutput
          }

          return {
            title: `Codebase Search: ${params.query}`,
            output,
            metadata: { count: result.contexts.length },
          }
        }).pipe(Effect.orDie),
    }
  }),
)