import { Injectable } from '@nestjs/common';
import { DataSource, Repository } from 'typeorm';
import { UsageAggregate } from '../../domain/entities/usage-aggregate.entity';

@Injectable()
export class UsageAggregateRepository {
  private readonly repo: Repository<UsageAggregate>;

  constructor(private readonly dataSource: DataSource) {
    this.repo = this.dataSource.getRepository(UsageAggregate);
  }

  async findByTenantAndPeriod(tenantId: string, year: number, month: number): Promise<UsageAggregate | null> {
    return this.repo.findOne({ where: { tenantId, year, month } });
  }

  async findCurrentMonth(tenantId: string): Promise<UsageAggregate | null> {
    const now = new Date();
    return this.findByTenantAndPeriod(tenantId, now.getFullYear(), now.getMonth() + 1);
  }

  async findHistoryByTenantId(tenantId: string, limit = 12): Promise<UsageAggregate[]> {
    return this.repo.find({
      where: { tenantId },
      order: { year: 'DESC', month: 'DESC' } as any,
      take: limit,
    });
  }

  async upsertTokens(
    tenantId: string,
    year: number,
    month: number,
    inputTokens: number,
    outputTokens: number,
    costUsd: number,
  ): Promise<void> {
    const periodStart = new Date(year, month - 1, 1);
    const periodEnd = new Date(year, month, 0, 23, 59, 59); // last day of month

    await this.dataSource.query(
      `
      INSERT INTO billing_usage_aggregates
        (id, tenant_id, year, month, period_start, period_end,
         total_input_tokens, total_output_tokens, total_tokens,
         total_cost_usd, task_count, updated_at)
      VALUES
        (gen_random_uuid(), $1, $2, $3, $4, $5, $6, $7, $8, $9, 1, NOW())
      ON CONFLICT (tenant_id, year, month)
      DO UPDATE SET
        total_input_tokens = billing_usage_aggregates.total_input_tokens + EXCLUDED.total_input_tokens,
        total_output_tokens = billing_usage_aggregates.total_output_tokens + EXCLUDED.total_output_tokens,
        total_tokens = billing_usage_aggregates.total_tokens + EXCLUDED.total_tokens,
        total_cost_usd = billing_usage_aggregates.total_cost_usd + EXCLUDED.total_cost_usd,
        task_count = billing_usage_aggregates.task_count + 1,
        updated_at = NOW()
      `,
      [
        tenantId, year, month, periodStart, periodEnd,
        inputTokens, outputTokens, inputTokens + outputTokens, costUsd,
      ],
    );
  }

  async save(aggregate: UsageAggregate): Promise<UsageAggregate> {
    return this.repo.save(aggregate);
  }
}
