import { Injectable, Logger } from '@nestjs/common'
import { InjectModel } from '@nestjs/mongoose'
import { Model } from 'mongoose'
import Anthropic from '@anthropic-ai/sdk'
import { ConfigService } from '@nestjs/config'
import { AgentSession, AgentSessionDocument } from '../common/schemas'
import { AgentToolsService } from './agent-tools.service'
import { CaseSituationAnalystService } from './case-analyst.service'
import { DocumentClassifierService } from '../document-classifier/document-classifier.service'
import type { MessageParam, ToolUseBlock, ToolResultBlockParam } from '@anthropic-ai/sdk/resources/messages'

const SYSTEM_PROMPT = `You are the Prompt Analyst — the executive secretary of a Thai law firm (GPS Legal / Soi96 Legal).

You are the SOLE interface between the attorney and the firm's systems. The attorney communicates only with you. You retrieve information, triage communications, and present clear briefings.

ROLE:
- Interpret what the attorney needs: research, comms triage, operational tasks, document classification
- Always use tools to retrieve live data before answering — never guess at names, dates, or case details
- Triage pending emails — surface items that need routing and recommend the correct client/matter when obvious
- Brief the attorney on items needing attention without being asked
- Never speculate on legal outcomes — only retrieve and present what is in the record

BEHAVIOUR:
- At the start of a new conversation, check for pending emails (list_pending_emails) and upcoming hearings (get_calendar) proactively
- When the attorney mentions a client by name, call search_clients first, then get_client_context
- When routing an email, explain your reasoning before calling associate_email — if confident, proceed; if ambiguous, ask first
- Keep responses concise and structured — the attorney is busy
- Use bullet points for lists; use plain numbers for dates and figures
- When you see Thai-language content in email subjects or names, handle it naturally

FIRM CONTEXT:
- Practice areas: immigration, corporate/BOI, civil litigation, property, employment
- Primary jurisdiction: Thailand
- Currency: primarily THB, also USD/EUR for international clients
- The attorney is the only licensed lawyer; a founding partner is retiring within the decade
- Matters are referenced by matterNumber (e.g. TM.7, BOI-24-001)

DOCUMENT HANDLING:
- When the attorney mentions or attaches a document, call classify_document FIRST — before any other action
- classify_document returns: document type, practice area, matter reference, client reference, and recommended action
- Only after classification do you route: case documents → delegate_to_case_analyst; comms documents → comms tools; financial docs → delegate_to_case_analyst (billing track)
- Pass the classification result as document_context when delegating to the Case Analyst

ROUTING RULES:
- Case/research work → delegate_to_case_analyst (client research, matter analysis, statute questions, form retrieval, law retrieval)
- Operational/comms work → use the operational tools below (emails, calendar, invoices)
- You never call the RAG Agent directly — that is the Case Analyst's job
- You never call Client Managers directly — delegate to Case Analyst
- Operational tools (list_pending_emails, associate_email, get_calendar, get_overdue_invoices) are YOUR tools — use them directly for the operational track

LIMITS:
- You route communications; you do not draft without being asked
- You confirm email associations when clear; you ask when genuinely ambiguous
- You never write directly to client records — only through the tools provided`

@Injectable()
export class PromptAnalystService {
  private readonly logger = new Logger(PromptAnalystService.name)
  private readonly anthropic: Anthropic
  private readonly MODEL = 'claude-sonnet-4-6'

  constructor(
    @InjectModel(AgentSession.name) private sessionModel: Model<AgentSessionDocument>,
    private readonly tools: AgentToolsService,
    private readonly caseAnalyst: CaseSituationAnalystService,
    private readonly classifier: DocumentClassifierService,
    private readonly config: ConfigService,
  ) {
    this.anthropic = new Anthropic({
      apiKey: config.get<string>('ANTHROPIC_API_KEY'),
    })
  }

  // ── Tool definitions ───────────────────────────────────────────────────────

  private get CLASSIFY_TOOL() {
    return {
      name: 'classify_document',
      description: 'Classify an incoming document BEFORE any routing decision. Identifies document type, practice area, matter reference, client reference, recommended action, and any deadline flags. Call this first whenever a document is involved.',
      input_schema: {
        type: 'object' as const,
        properties: {
          document_text: { type: 'string', description: 'Full text content of the document to classify' },
          filename:      { type: 'string', description: 'Optional filename or document title for context (e.g. "TM7_chen.pdf")' },
        },
        required: ['document_text'],
      },
    }
  }

  private get DELEGATE_TOOL() {
    return {
      name: 'delegate_to_case_analyst',
      description: 'Delegate a case/research task to the Case/Situation Analyst. Use for: client research, matter analysis, statute questions, form retrieval, law retrieval, or any task requiring access to case data or specialist agents.',
      input_schema: {
        type: 'object' as const,
        properties: {
          task: { type: 'string', description: 'Clear description of what the Case Analyst needs to do or find out' },
          practice_area: { type: 'string', description: 'Practice area if known (immigration, corporate, property, employment, tax, civil_litigation, family)' },
          matter_id: { type: 'string', description: 'Specific matter ID if the task is matter-scoped' },
          client_folder_id: { type: 'string', description: 'Specific client folder ID if already identified' },
          document_context: { type: 'string', description: 'Document Classifier output if a document was involved' },
          urgency: { type: 'string', enum: ['routine', 'urgent'], description: 'Task urgency' },
        },
        required: ['task'],
      },
    }
  }

  async createSession(): Promise<AgentSessionDocument> {
    const { nanoid } = await import('nanoid')
    return new this.sessionModel({ sessionId: nanoid(16) }).save()
  }

  async chat(sessionId: string | undefined, userMessage: string): Promise<{
    response: string
    sessionId: string
    toolsUsed: string[]
  }> {
    // Load or create session
    let session: AgentSessionDocument | null = null
    if (sessionId) {
      session = await this.sessionModel.findOne({ sessionId }).exec()
    }
    if (!session) {
      session = await this.createSession()
    }

    const messages: MessageParam[] = [
      ...(session.messages as MessageParam[]),
      { role: 'user', content: userMessage },
    ]

    const toolsUsed: string[] = []

    // Agentic tool-use loop
    while (true) {
      const allTools = [
        this.CLASSIFY_TOOL,
        this.DELEGATE_TOOL,
        ...this.tools.getToolDefinitions(),
      ]

      const response = await this.anthropic.messages.create({
        model:      this.MODEL,
        max_tokens: 4096,
        system:     SYSTEM_PROMPT,
        tools:      allTools as any,
        messages,
      })

      messages.push({ role: 'assistant', content: response.content })

      if (response.stop_reason === 'end_turn') {
        const text = response.content
          .filter(b => b.type === 'text')
          .map(b => (b as any).text)
          .join('')

        // Persist updated conversation
        session.messages = messages as any
        await session.save()

        return { response: text, sessionId: session.sessionId, toolsUsed }
      }

      if (response.stop_reason === 'tool_use') {
        const toolBlocks = response.content.filter(b => b.type === 'tool_use') as ToolUseBlock[]
        const toolResults: ToolResultBlockParam[] = []

        for (const block of toolBlocks) {
          toolsUsed.push(block.name)
          this.logger.debug(`Tool call: ${block.name}`)
          try {
            let result: any
            if (block.name === 'classify_document') {
              const inp = block.input as any
              result = await this.classifier.classifyAndResolve(inp.document_text, inp.filename)
            } else if (block.name === 'delegate_to_case_analyst') {
              const inp = block.input as any
              result = await this.caseAnalyst.handle({
                task:             inp.task,
                practiceArea:     inp.practice_area,
                matterId:         inp.matter_id,
                clientFolderId:   inp.client_folder_id,
                documentContext:  inp.document_context,
                urgency:          inp.urgency,
              })
            } else {
              result = await this.tools.execute(block.name, block.input)
            }
            toolResults.push({
              type:        'tool_result',
              tool_use_id: block.id,
              content:     JSON.stringify(result),
            })
          } catch (err: any) {
            toolResults.push({
              type:        'tool_result',
              tool_use_id: block.id,
              content:     JSON.stringify({ error: err.message }),
              is_error:    true,
            })
          }
        }

        messages.push({ role: 'user', content: toolResults })
      }
    }
  }

  async getSession(sessionId: string): Promise<AgentSessionDocument | null> {
    return this.sessionModel.findOne({ sessionId }).exec()
  }
}
