import { Injectable, NotFoundException, BadRequestException } from '@nestjs/common'
import { InjectModel } from '@nestjs/mongoose'
import { Model } from 'mongoose'
import {
  WorkflowTemplate, WorkflowTemplateDocument,
  MatterWorkflow, MatterWorkflowDocument,
  Matter, MatterDocument,
} from '../common/schemas'
import { CreateWorkflowTemplateDto } from './dto/create-workflow-template.dto'
import { UpdateWorkflowTemplateDto } from './dto/update-workflow-template.dto'
import { InstantiateWorkflowDto } from './dto/instantiate-workflow.dto'
import { UpdateStepDto } from './dto/update-step.dto'

@Injectable()
export class WorkflowsService {
  constructor(
    @InjectModel(WorkflowTemplate.name) private templateModel: Model<WorkflowTemplateDocument>,
    @InjectModel(MatterWorkflow.name)   private workflowModel: Model<MatterWorkflowDocument>,
    @InjectModel(Matter.name)           private matterModel:   Model<MatterDocument>,
  ) {}

  // ── Template CRUD ──────────────────────────────────────────────────────────

  async createTemplate(dto: CreateWorkflowTemplateDto, createdBy?: string): Promise<WorkflowTemplateDocument> {
    return this.templateModel.create({ ...dto, createdBy })
  }

  async findAllTemplates(practiceArea?: string): Promise<WorkflowTemplateDocument[]> {
    const filter: any = { isActive: true }
    if (practiceArea) filter.practiceArea = { $in: [practiceArea, 'universal'] }
    return this.templateModel.find(filter).sort({ name: 1 }).lean() as any
  }

  async findOneTemplate(id: string): Promise<WorkflowTemplateDocument> {
    const doc = await this.templateModel.findById(id).lean() as any
    if (!doc) throw new NotFoundException(`WorkflowTemplate ${id} not found`)
    return doc
  }

  async updateTemplate(id: string, dto: UpdateWorkflowTemplateDto): Promise<WorkflowTemplateDocument> {
    const doc = await this.templateModel.findByIdAndUpdate(id, dto, { new: true }).lean() as any
    if (!doc) throw new NotFoundException(`WorkflowTemplate ${id} not found`)
    return doc
  }

  async removeTemplate(id: string): Promise<void> {
    const doc = await this.templateModel.findById(id)
    if (!doc) throw new NotFoundException(`WorkflowTemplate ${id} not found`)
    if (doc.isSystem) throw new BadRequestException('System workflow templates cannot be deleted')
    await doc.deleteOne()
  }

  // ── Instantiate ────────────────────────────────────────────────────────────

  async instantiate(dto: InstantiateWorkflowDto): Promise<MatterWorkflowDocument> {
    const template = await this.templateModel.findById(dto.templateId)
    if (!template) throw new NotFoundException(`WorkflowTemplate ${dto.templateId} not found`)

    const matter = await this.matterModel.findById(dto.matterId).lean()
    if (!matter) throw new NotFoundException(`Matter ${dto.matterId} not found`)

    const matterOpenedDate = (matter as any).openedDate ?? new Date()

    // Build live steps from template definitions
    const steps = template.steps
      .slice()
      .sort((a, b) => a.order - b.order)
      .map(def => {
        let dueDate: Date | undefined
        if (def.deadlineDays != null) {
          dueDate = new Date(matterOpenedDate)
          dueDate.setDate(dueDate.getDate() + def.deadlineDays)
        }
        return {
          stepId: def.stepId,
          order: def.order,
          title: def.title,
          description: def.description,
          mandatory: def.mandatory,
          linkedFormTemplateId: def.linkedFormTemplateId,
          status: 'pending' as const,
          dueDate,
        }
      })

    return this.workflowModel.create({
      matterId: dto.matterId,
      clientFolderId: String((matter as any).clientFolderId),
      templateId: dto.templateId,
      templateName: template.name,
      steps,
      instantiatedBy: dto.instantiatedBy,
      notes: dto.notes,
    })
  }

  // ── MatterWorkflow queries ─────────────────────────────────────────────────

  async findByMatter(matterId: string): Promise<MatterWorkflowDocument[]> {
    return this.workflowModel.find({ matterId }).sort({ createdAt: -1 }).lean() as any
  }

  async findOneWorkflow(id: string): Promise<MatterWorkflowDocument> {
    const doc = await this.workflowModel.findById(id).lean() as any
    if (!doc) throw new NotFoundException(`MatterWorkflow ${id} not found`)
    return doc
  }

  // ── Step updates ───────────────────────────────────────────────────────────

  async updateStep(
    workflowId: string,
    stepId: string,
    dto: UpdateStepDto,
  ): Promise<MatterWorkflowDocument> {
    const workflow = await this.workflowModel.findById(workflowId)
    if (!workflow) throw new NotFoundException(`MatterWorkflow ${workflowId} not found`)

    const step = workflow.steps.find(s => s.stepId === stepId)
    if (!step) throw new NotFoundException(`Step ${stepId} not found in workflow ${workflowId}`)

    step.status = dto.status
    if (dto.notes !== undefined) step.notes = dto.notes
    if (dto.dueDate) step.dueDate = new Date(dto.dueDate)
    if (dto.status === 'completed') {
      step.completedAt = new Date()
      step.completedBy = dto.completedBy
    }

    // Auto-complete workflow if all mandatory steps done
    const allMandatoryDone = workflow.steps
      .filter(s => s.mandatory)
      .every(s => s.status === 'completed' || s.status === 'skipped')
    if (allMandatoryDone && workflow.status === 'active') {
      workflow.status = 'completed'
      workflow.completedAt = new Date()
    }

    await workflow.save()
    return workflow.toObject() as MatterWorkflowDocument
  }

  // ── Overdue steps dashboard query ──────────────────────────────────────────

  async getOverdueSteps(): Promise<{ workflowId: string; matterId: string; templateName: string; step: any }[]> {
    const now = new Date()
    const workflows = await this.workflowModel.find({ status: 'active' }).lean() as any[]
    const result: any[] = []
    for (const wf of workflows) {
      for (const step of wf.steps) {
        if (step.status === 'pending' && step.dueDate && new Date(step.dueDate) < now) {
          result.push({
            workflowId: String((wf as any)._id),
            matterId: wf.matterId,
            templateName: wf.templateName,
            step,
          })
        }
      }
    }
    return result
  }
}
