import { Injectable, NotFoundException } from '@nestjs/common'
import { InjectModel } from '@nestjs/mongoose'
import { Model, Types } from 'mongoose'
import { TimeEntry, TimeEntryDocument } from '../common/schemas'
import { CreateTimeEntryDto } from './dto/create-time-entry.dto'
import { UpdateTimeEntryDto } from './dto/update-time-entry.dto'

@Injectable()
export class TimeEntriesService {
  constructor(
    @InjectModel(TimeEntry.name) private timeModel: Model<TimeEntryDocument>,
  ) {}

  async create(dto: CreateTimeEntryDto): Promise<TimeEntryDocument> {
    const entry = new this.timeModel({ ...dto, billed: dto.billed ?? false })
    return entry.save()
  }

  async findAll(filters: {
    matterId?: string
    clientFolderId?: string
    attorney?: string
    billed?: boolean
    from?: string
    to?: string
    limit?: number
    offset?: number
  }): Promise<{ items: TimeEntryDocument[]; total: number }> {
    const query: any = {}
    if (filters.matterId) query.matterId = new Types.ObjectId(filters.matterId)
    if (filters.clientFolderId) query.clientFolderId = new Types.ObjectId(filters.clientFolderId)
    if (filters.attorney) query.attorney = filters.attorney
    if (filters.billed !== undefined) query.billed = filters.billed
    if (filters.from || filters.to) {
      query.date = {}
      if (filters.from) query.date.$gte = new Date(filters.from)
      if (filters.to) query.date.$lte = new Date(filters.to)
    }

    const [items, total] = await Promise.all([
      this.timeModel.find(query)
        .sort({ date: -1 })
        .skip(filters.offset ?? 0)
        .limit(filters.limit ?? 100)
        .exec(),
      this.timeModel.countDocuments(query),
    ])
    return { items, total }
  }

  async findOne(id: string): Promise<TimeEntryDocument> {
    const entry = await this.timeModel.findById(id).exec()
    if (!entry) throw new NotFoundException(`Time entry ${id} not found`)
    return entry
  }

  async update(id: string, dto: UpdateTimeEntryDto): Promise<TimeEntryDocument> {
    const entry = await this.timeModel.findByIdAndUpdate(id, dto, { new: true }).exec()
    if (!entry) throw new NotFoundException(`Time entry ${id} not found`)
    return entry as TimeEntryDocument
  }

  async markBilled(ids: string[], invoiceRef: string): Promise<{ updated: number }> {
    const result = await this.timeModel.updateMany(
      { _id: { $in: ids.map(id => new Types.ObjectId(id)) }, billed: false },
      { billed: true, invoiceRef },
    ).exec()
    return { updated: result.modifiedCount }
  }

  async getSummary(matterId: string): Promise<{
    totalMinutes: number
    billedMinutes: number
    unbilledMinutes: number
    totalAmount: number
  }> {
    const entries = await this.timeModel.find({ matterId: new Types.ObjectId(matterId) }).lean().exec()
    const totalMinutes = entries.reduce((s, e) => s + (e.durationMinutes ?? 0), 0)
    const billedMinutes = entries.filter(e => e.billed).reduce((s, e) => s + (e.durationMinutes ?? 0), 0)
    const totalAmount = entries.reduce((s, e) => s + ((e.durationMinutes ?? 0) / 60) * (e.ratePerHour ?? 0), 0)
    return {
      totalMinutes,
      billedMinutes,
      unbilledMinutes: totalMinutes - billedMinutes,
      totalAmount,
    }
  }
}
