/**
 * CaseSituationAnalystService — Agent #4 in the hierarchy.
 *
 * Receives pre-classified, context-rich requests from the Prompt Analyst.
 * Coordinates Client Managers and calls specialist agents:
 *   - RAG Agent  (statute/form/law retrieval)
 *   - Billing Agent (financial data)
 *   - Judicial Intelligence / Adversary Intelligence (future)
 *
 * Communication rules (enforced here):
 *   MAY call: Client Managers, RAG Agent, Billing Agent, Judicial/Adversary Intel
 *   MAY NOT call: Prompt Analyst, Onboarding Agent, Comms Agent
 *   Reports back to: Prompt Analyst only
 *
 * The Case Analyst never communicates directly with the attorney.
 */

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 type { Tool, MessageParam, ToolUseBlock, ToolResultBlockParam } from '@anthropic-ai/sdk/resources/messages'
import {
  ClientFolder, ClientFolderDocument,
  Matter, MatterDocument,
  LawCorpusEntry, LawCorpusEntryDocument,
  FormTemplate, FormTemplateDocument,
} from '../common/schemas'
import { RagAgentService, LawRetrievalContext } from '../rag-agent/rag-agent.service'

// ─── Request/Response types ───────────────────────────────────────────────────

export interface CaseAnalystRequest {
  task: string                    // what the Prompt Analyst needs done
  practiceArea?: string           // if known from Document Classifier
  matterId?: string               // specific matter if request is matter-scoped
  clientFolderId?: string         // specific client if already identified
  documentContext?: string        // Document Classifier output (if a document was involved)
  urgency?: 'routine' | 'urgent'
}

export interface CaseAnalystResponse {
  summary: string                 // structured response back to Prompt Analyst
  toolsUsed: string[]
  retrievedAt: string
}

// ─── System prompt ────────────────────────────────────────────────────────────

const SYSTEM_PROMPT = `You are the Case/Situation Analyst — the senior associate of a Thai law firm (GPS Legal).

You receive delegated tasks from the Prompt Analyst. You coordinate specialist agents and data sources to fulfil those tasks.

YOUR ROLE:
- Analyse what data and specialist input is needed to answer the request
- Call the appropriate tools in the correct order
- Synthesise results into a clear, structured response for the Prompt Analyst
- The Prompt Analyst will present your findings to the attorney — your output must be briefing-quality

YOUR TOOLS:
- get_client_context: retrieve full client profile and matter history for a specific client
- search_matters: find matters by practice area, status, or keyword
- retrieve_stock_forms: trigger the RAG Agent to download/refresh official Thai government forms from government websites
- fetch_laws: trigger the RAG Agent to retrieve current laws, circulars, and policy updates for a given practice area
- search_law_corpus: search the firm's already-indexed law corpus by practice area or keyword
- search_form_library: list available stock forms for a given practice area

RULES:
- You call specialist agents (RAG Agent via retrieve_stock_forms/fetch_laws) when statute or form retrieval is required
- You never communicate directly with the attorney — only with the Prompt Analyst via your response
- You never write to client records directly — use the designated tools only
- If a task requires data you cannot retrieve with available tools, say so clearly

FIRM CONTEXT:
- Practice areas: immigration, corporate, civil_litigation, property, family, employment, tax
- Primary jurisdiction: Thailand
- Stock form library covers: Immigration Bureau (TM.7, TM.8, TM.28, TM.30, TM.47), Department of Employment (WP.1, WP.10), DBD, BOI, Revenue Department, Land Department
- Law corpus covers Thai legislation applicable to each practice area`

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

  constructor(
    @InjectModel(ClientFolder.name) private folderModel: Model<ClientFolderDocument>,
    @InjectModel(Matter.name)       private matterModel: Model<MatterDocument>,
    @InjectModel(LawCorpusEntry.name) private lawModel: Model<LawCorpusEntryDocument>,
    @InjectModel(FormTemplate.name) private templateModel: Model<FormTemplateDocument>,
    private readonly ragAgent: RagAgentService,
    private readonly config: ConfigService,
  ) {
    this.anthropic = new Anthropic({ apiKey: config.get<string>('ANTHROPIC_API_KEY') })
  }

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

  private get TOOLS(): Tool[] {
    return [
      {
        name: 'get_client_context',
        description: 'Retrieve full client profile, all matters, and recent activity for a specific client.',
        input_schema: {
          type: 'object' as const,
          properties: {
            clientFolderId: { type: 'string', description: 'MongoDB _id of the client folder' },
          },
          required: ['clientFolderId'],
        },
      },
      {
        name: 'search_matters',
        description: 'Search for matters by practice area, status, or keyword. Use when the task involves finding relevant matters.',
        input_schema: {
          type: 'object' as const,
          properties: {
            practiceArea: { type: 'string', description: 'Filter by practice area (optional)' },
            status:       { type: 'string', description: 'Filter by status: open | closed | pending (optional)' },
            keyword:      { type: 'string', description: 'Keyword to search in matter title or reference number (optional)' },
          },
          required: [],
        },
      },
      {
        name: 'retrieve_stock_forms',
        description: 'Trigger the RAG Agent to browse official Thai government websites and download current versions of all stock forms (TM.7, TM.8, WP.1, etc.). Use when forms need to be refreshed or when the library is being initialised.',
        input_schema: {
          type: 'object' as const,
          properties: {},
          required: [],
        },
      },
      {
        name: 'fetch_laws',
        description: 'Trigger the RAG Agent to retrieve current laws, circulars, regulations, and policy updates from official Thai government sources for a specific practice area.',
        input_schema: {
          type: 'object' as const,
          properties: {
            practiceArea: {
              type: 'string',
              enum: ['immigration', 'corporate', 'property', 'employment', 'tax', 'civil_litigation', 'family'],
              description: 'The practice area to retrieve laws for',
            },
            keywords: {
              type: 'array',
              items: { type: 'string' },
              description: 'Optional additional search keywords (e.g. specific act name, section, visa type)',
            },
            matterId: { type: 'string', description: 'Optional: matter ID that triggered this retrieval' },
          },
          required: ['practiceArea'],
        },
      },
      {
        name: 'search_law_corpus',
        description: 'Search the firm\'s already-indexed law corpus for relevant statutes or circulars. Use before fetch_laws to check if applicable law is already indexed.',
        input_schema: {
          type: 'object' as const,
          properties: {
            practiceArea: { type: 'string', description: 'Filter by practice area' },
            keyword:      { type: 'string', description: 'Keyword to search in titles and tags' },
          },
          required: [],
        },
      },
      {
        name: 'search_form_library',
        description: 'List available stock forms for a given practice area, showing which ones have been downloaded and which are pending.',
        input_schema: {
          type: 'object' as const,
          properties: {
            practiceArea: { type: 'string', description: 'Filter by practice area (optional — omit for all)' },
          },
          required: [],
        },
      },
    ]
  }

  // ── Tool implementations ────────────────────────────────────────────────────

  private async toolGetClientContext(clientFolderId: string) {
    const [folder, matters] = await Promise.all([
      this.folderModel.findById(clientFolderId).lean(),
      this.matterModel.find({ clientFolderId })
        .select('_id matterNumber title status practiceArea openedAt closedAt')
        .sort({ openedAt: -1 }).lean(),
    ])
    return { folder, matters }
  }

  private async toolSearchMatters(practiceArea?: string, status?: string, keyword?: string) {
    const filter: any = {}
    if (practiceArea) filter.practiceArea = practiceArea
    if (status) filter.status = status
    if (keyword) filter.$or = [
      { title: { $regex: keyword, $options: 'i' } },
      { matterNumber: { $regex: keyword, $options: 'i' } },
    ]
    return this.matterModel.find(filter)
      .select('_id matterNumber title status practiceArea clientFolderId openedAt')
      .sort({ openedAt: -1 }).limit(20).lean()
  }

  private async toolRetrieveStockForms(): Promise<string> {
    this.logger.log('Case Analyst → RAG Agent: retrieve_stock_forms')
    // Fire-and-forget — form retrieval runs in background
    this.ragAgent.runFormRetrieval().catch(err =>
      this.logger.error('RAG Agent form retrieval failed:', err),
    )
    return 'RAG Agent started: browsing Thai government portals to download stock forms. This runs in the background. Check /rag-agent/status for progress.'
  }

  private async toolFetchLaws(context: LawRetrievalContext): Promise<string> {
    this.logger.log(`Case Analyst → RAG Agent: fetch_laws (${context.practiceArea})`)
    this.ragAgent.runLawRetrieval(context).catch(err =>
      this.logger.error('RAG Agent law retrieval failed:', err),
    )
    return `RAG Agent started: retrieving ${context.practiceArea} laws from Thai government sources. Running in background. Check /rag-agent/law-status for progress.`
  }

  private async toolSearchLawCorpus(practiceArea?: string, keyword?: string) {
    const filter: any = {}
    if (practiceArea) filter.practiceArea = practiceArea
    if (keyword) filter.$or = [
      { title: { $regex: keyword, $options: 'i' } },
      { tags: { $regex: keyword, $options: 'i' } },
    ]
    return this.lawModel.find(filter)
      .select('title lawType practiceArea issuedBy effectiveDate language sourceUrl retrievedBy createdAt')
      .sort({ createdAt: -1 }).limit(20).lean()
  }

  private async toolSearchFormLibrary(practiceArea?: string) {
    const filter: any = { isSystem: true }
    if (practiceArea) filter.practiceArea = { $in: [practiceArea, 'universal'] }
    const forms = await this.templateModel.find(filter)
      .select('name practiceArea stockId storageKey needsCalibration fillMode fields')
      .sort({ practiceArea: 1, name: 1 }).lean()
    return forms.map((f: any) => ({
      name: f.name,
      practiceArea: f.practiceArea,
      stockId: f.stockId,
      status: f.storageKey ? 'downloaded' : 'pending_retrieval',
      needsCalibration: f.needsCalibration,
      fieldCount: f.fields?.length ?? 0,
    }))
  }

  // ── Tool dispatcher ────────────────────────────────────────────────────────

  private async dispatchTool(name: string, input: any): Promise<any> {
    switch (name) {
      case 'get_client_context':  return this.toolGetClientContext(input.clientFolderId)
      case 'search_matters':      return this.toolSearchMatters(input.practiceArea, input.status, input.keyword)
      case 'retrieve_stock_forms': return this.toolRetrieveStockForms()
      case 'fetch_laws':          return this.toolFetchLaws({
        practiceArea: input.practiceArea,
        keywords: input.keywords,
        matterId: input.matterId,
      })
      case 'search_law_corpus':   return this.toolSearchLawCorpus(input.practiceArea, input.keyword)
      case 'search_form_library': return this.toolSearchFormLibrary(input.practiceArea)
      default: return { error: `Unknown tool: ${name}` }
    }
  }

  // ── Main entry point ────────────────────────────────────────────────────────

  async handle(request: CaseAnalystRequest): Promise<CaseAnalystResponse> {
    this.logger.log(`Case Analyst received task: ${request.task.slice(0, 80)}`)

    const userMessage = [
      `TASK: ${request.task}`,
      request.practiceArea ? `PRACTICE AREA: ${request.practiceArea}` : '',
      request.matterId     ? `MATTER ID: ${request.matterId}` : '',
      request.clientFolderId ? `CLIENT FOLDER ID: ${request.clientFolderId}` : '',
      request.documentContext ? `DOCUMENT CONTEXT: ${request.documentContext}` : '',
      request.urgency === 'urgent' ? 'URGENCY: Urgent — prioritise' : '',
    ].filter(Boolean).join('\n')

    const messages: MessageParam[] = [{ role: 'user', content: userMessage }]
    const toolsUsed: string[] = []

    let turns = 0
    const MAX_TURNS = 20

    while (turns < MAX_TURNS) {
      turns++

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

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

      if (response.stop_reason === 'end_turn') {
        const summary = response.content
          .filter((b: any) => b.type === 'text')
          .map((b: any) => b.text)
          .join('\n')
        return { summary, toolsUsed, retrievedAt: new Date().toISOString() }
      }

      if (response.stop_reason !== 'tool_use') break

      const toolResults: ToolResultBlockParam[] = []
      for (const block of response.content) {
        if (block.type !== 'tool_use') continue
        const tb = block as ToolUseBlock
        toolsUsed.push(tb.name)
        this.logger.debug(`Tool: ${tb.name}`)
        const result = await this.dispatchTool(tb.name, tb.input)
        toolResults.push({ type: 'tool_result', tool_use_id: tb.id, content: JSON.stringify(result) })
      }

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

    return {
      summary: 'Case Analyst completed without a final response (max turns reached or unexpected stop).',
      toolsUsed,
      retrievedAt: new Date().toISOString(),
    }
  }
}
