import { Injectable, Logger } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { BackupTarget, SnapshotStatus } from '@/domain/enums';
import { BackupResult } from '@/domain/interfaces/backup-handler.interface';

@Injectable()
export class SnapshotRepository {
  private readonly logger = new Logger(SnapshotRepository.name);

  constructor(private readonly prisma: PrismaService) {}

  async createTask(data: {
    storageType: string;
    storagePath: string;
    targets: BackupTarget[];
  }) {
    return this.prisma.snapshotTask.create({
      data: {
        storageType: data.storageType,
        storagePath: data.storagePath,
        targets: JSON.stringify(data.targets),
        status: SnapshotStatus.PENDING,
        details: {
          create: data.targets.map((target) => ({
            target,
            status: SnapshotStatus.PENDING,
          })),
        },
      },
      include: { details: true },
    });
  }

  async findById(id: string) {
    return this.prisma.snapshotTask.findUnique({
      where: { id },
      include: { details: true },
    });
  }

  async findAll(page: number = 1, limit: number = 20) {
    const skip = (page - 1) * limit;
    const [tasks, total] = await Promise.all([
      this.prisma.snapshotTask.findMany({
        skip,
        take: limit,
        orderBy: { createdAt: 'desc' },
        include: { details: true },
      }),
      this.prisma.snapshotTask.count(),
    ]);
    return { tasks, total, page, limit };
  }

  async updateTaskStatus(id: string, status: SnapshotStatus, error?: string) {
    const data: Record<string, unknown> = { status };
    if (status === SnapshotStatus.RUNNING) {
      data.startedAt = new Date();
    }
    if (status === SnapshotStatus.COMPLETED || status === SnapshotStatus.FAILED) {
      data.completedAt = new Date();
    }
    if (error) {
      data.error = error;
    }
    return this.prisma.snapshotTask.update({ where: { id }, data });
  }

  async updateDetailStatus(taskId: string, target: string, status: SnapshotStatus) {
    const detail = await this.prisma.snapshotDetail.findFirst({
      where: { taskId, target },
    });
    if (!detail) return;

    const data: Record<string, unknown> = { status };
    if (status === SnapshotStatus.RUNNING) {
      data.startedAt = new Date();
    }
    return this.prisma.snapshotDetail.update({ where: { id: detail.id }, data });
  }

  async updateDetailProgress(taskId: string, target: string, progress: number, progressMsg?: string) {
    const detail = await this.prisma.snapshotDetail.findFirst({
      where: { taskId, target },
    });
    if (!detail) return;
    const data: Record<string, unknown> = { progress };
    if (progressMsg !== undefined) data.progressMsg = progressMsg;
    return this.prisma.snapshotDetail.update({
      where: { id: detail.id },
      data,
    });
  }

  async completeDetail(taskId: string, target: string, result: BackupResult) {
    const detail = await this.prisma.snapshotDetail.findFirst({
      where: { taskId, target },
    });
    if (!detail) return;
    return this.prisma.snapshotDetail.update({
      where: { id: detail.id },
      data: {
        status: SnapshotStatus.COMPLETED,
        progress: 100,
        fileSize: BigInt(result.fileSize),
        fileName: result.fileName,
        completedAt: new Date(),
      },
    });
  }

  async failDetail(taskId: string, target: string, error: string) {
    const detail = await this.prisma.snapshotDetail.findFirst({
      where: { taskId, target },
    });
    if (!detail) return;
    return this.prisma.snapshotDetail.update({
      where: { id: detail.id },
      data: {
        status: SnapshotStatus.FAILED,
        error,
        completedAt: new Date(),
      },
    });
  }

  async completeTask(id: string) {
    const details = await this.prisma.snapshotDetail.findMany({
      where: { taskId: id },
    });

    const totalSize = details.reduce((sum, d) => sum + d.fileSize, BigInt(0));
    const hasFailure = details.some((d) => d.status === SnapshotStatus.FAILED);
    const allFailed = details.every((d) => d.status === SnapshotStatus.FAILED);

    return this.prisma.snapshotTask.update({
      where: { id },
      data: {
        status: allFailed ? SnapshotStatus.FAILED : SnapshotStatus.COMPLETED,
        totalSize,
        completedAt: new Date(),
        error: hasFailure ? '部分备份目标失败，请查看详情' : null,
      },
    });
  }

  async deleteTask(id: string) {
    return this.prisma.snapshotTask.delete({ where: { id } });
  }

  async findByStatus(status: SnapshotStatus) {
    return this.prisma.snapshotTask.findMany({
      where: { status },
      include: { details: true },
    });
  }

  async findExpiredLocalTasks(retentionHours: number) {
    const threshold = new Date(Date.now() - retentionHours * 60 * 60 * 1000);
    return this.prisma.snapshotTask.findMany({
      where: {
        storageType: 'LOCAL',
        createdAt: { lt: threshold },
      },
      include: { details: true },
    });
  }
}
