import fs from 'fs/promises'
import path from 'path'
import * as z from 'zod'

import { logger, validatePath } from '../types'

// Schema definition
export const WriteToolSchema = z.object({
  file_path: z.string().describe('The path to the file to write'),
  content: z.string().describe('The content to write to the file')
})

// Tool definition with detailed description
export const writeToolDefinition = {
  name: 'write',
  description: `Writes a file to the local filesystem.

- This tool will overwrite the existing file if one exists at the path
- You MUST use the read tool first to understand what you're overwriting
- ALWAYS prefer using the 'edit' tool for existing files
- NEVER proactively create documentation files unless explicitly requested
- Parent directories will be created automatically if they don't exist
- The file_path must resolve within the configured workspace root`,
  inputSchema: z.toJSONSchema(WriteToolSchema)
}

// Handler implementation
export async function handleWriteTool(args: unknown, baseDir: string) {
  const parsed = WriteToolSchema.safeParse(args)
  if (!parsed.success) {
    throw new Error(`Invalid arguments for write: ${parsed.error}`)
  }

  const filePath = parsed.data.file_path
  const validPath = await validatePath(filePath, baseDir)

  // Create parent directory if it doesn't exist
  const parentDir = path.dirname(validPath)
  try {
    await fs.mkdir(parentDir, { recursive: true })
  } catch (error: any) {
    if (error.code !== 'EEXIST') {
      throw new Error(`Failed to create parent directory: ${error.message}`)
    }
  }

  // Check if file exists (for logging)
  let isOverwrite = false
  try {
    await fs.stat(validPath)
    isOverwrite = true
  } catch {
    // File doesn't exist, that's fine
  }

  // Write the file
  try {
    await fs.writeFile(validPath, parsed.data.content, 'utf-8')
  } catch (error: any) {
    throw new Error(`Failed to write file: ${error.message}`)
  }

  // Log the operation
  logger.info('File written', {
    path: validPath,
    overwrite: isOverwrite,
    size: parsed.data.content.length
  })

  // Format output
  const relativePath = path.relative(baseDir, validPath)
  const action = isOverwrite ? 'Updated' : 'Created'
  const lines = parsed.data.content.split('\n').length

  return {
    content: [
      {
        type: 'text',
        text: `${action} file: ${relativePath}\n` + `Size: ${parsed.data.content.length} bytes\n` + `Lines: ${lines}`
      }
    ]
  }
}
