import { Injectable, Logger } from "@nestjs/common";
import { PrismaService } from "../prisma/prisma.service";
import { ActivityAction, EntityType, Prisma, ActivityLog } from "@prisma/client";
import type {
  CreateActivityLogInput,
  PaginatedActivityLogs,
  ActivityLogResult,
} from "./interfaces/activity.interface";
import type { QueryActivityLogDto } from "./dto";

/**
 * Service for managing activity logs and audit trails
 */
@Injectable()
export class ActivityService {
  private readonly logger = new Logger(ActivityService.name);

  constructor(private readonly prisma: PrismaService) {}

  /**
   * Create a new activity log entry (fire-and-forget)
   *
   * Activity logging failures are logged but never propagate to callers.
   * This ensures activity logging never breaks primary operations.
   *
   * @returns The created ActivityLog or null if logging failed
   */
  async logActivity(input: CreateActivityLogInput): Promise<ActivityLog | null> {
    try {
      return await this.prisma.activityLog.create({
        data: input as unknown as Prisma.ActivityLogCreateInput,
      });
    } catch (error) {
      // Log the error but don't propagate - activity logging is fire-and-forget
      this.logger.error(
        `Failed to log activity: action=${input.action} entityType=${input.entityType} entityId=${input.entityId}`,
        error instanceof Error ? error.stack : String(error)
      );
      return null;
    }
  }

  /**
   * Get paginated activity logs with filters
   */
  async findAll(query: QueryActivityLogDto): Promise<PaginatedActivityLogs> {
    const page = query.page ?? 1;
    const limit = query.limit ?? 50;
    const skip = (page - 1) * limit;

    // Build where clause
    const where: Prisma.ActivityLogWhereInput = {};

    if (query.workspaceId !== undefined) {
      where.workspaceId = query.workspaceId;
    }

    if (query.userId) {
      where.userId = query.userId;
    }

    if (query.action) {
      where.action = query.action;
    }

    if (query.entityType) {
      where.entityType = query.entityType;
    }

    if (query.entityId) {
      where.entityId = query.entityId;
    }

    if (query.startDate ?? query.endDate) {
      where.createdAt = {};
      if (query.startDate) {
        where.createdAt.gte = query.startDate;
      }
      if (query.endDate) {
        where.createdAt.lte = query.endDate;
      }
    }

    // Execute queries in parallel
    const [data, total] = await Promise.all([
      this.prisma.activityLog.findMany({
        where,
        include: {
          user: {
            select: {
              id: true,
              name: true,
              email: true,
            },
          },
        },
        orderBy: {
          createdAt: "desc",
        },
        skip,
        take: limit,
      }),
      this.prisma.activityLog.count({ where }),
    ]);

    return {
      data,
      meta: {
        total,
        page,
        limit,
        totalPages: Math.ceil(total / limit),
      },
    };
  }

  /**
   * Get a single activity log by ID
   */
  async findOne(id: string, workspaceId?: string): Promise<ActivityLogResult | null> {
    const where: Prisma.ActivityLogWhereUniqueInput = { id };
    if (workspaceId) {
      where.workspaceId = workspaceId;
    }
    return await this.prisma.activityLog.findUnique({
      where,
      include: {
        user: {
          select: {
            id: true,
            name: true,
            email: true,
          },
        },
      },
    });
  }

  /**
   * Get audit trail for a specific entity
   */
  async getAuditTrail(
    workspaceId: string,
    entityType: EntityType,
    entityId: string
  ): Promise<ActivityLogResult[]> {
    return await this.prisma.activityLog.findMany({
      where: {
        workspaceId,
        entityType,
        entityId,
      },
      include: {
        user: {
          select: {
            id: true,
            name: true,
            email: true,
          },
        },
      },
      orderBy: {
        createdAt: "asc",
      },
    });
  }

  // ============================================
  // HELPER METHODS FOR COMMON ACTIVITY TYPES
  // ============================================

  /**
   * Log task creation
   */
  async logTaskCreated(
    workspaceId: string,
    userId: string,
    taskId: string,
    details?: Prisma.JsonValue
  ): Promise<ActivityLog | null> {
    return this.logActivity({
      workspaceId,
      userId,
      action: ActivityAction.CREATED,
      entityType: EntityType.TASK,
      entityId: taskId,
      ...(details && { details }),
    });
  }

  /**
   * Log task update
   */
  async logTaskUpdated(
    workspaceId: string,
    userId: string,
    taskId: string,
    details?: Prisma.JsonValue
  ): Promise<ActivityLog | null> {
    return this.logActivity({
      workspaceId,
      userId,
      action: ActivityAction.UPDATED,
      entityType: EntityType.TASK,
      entityId: taskId,
      ...(details && { details }),
    });
  }

  /**
   * Log task deletion
   */
  async logTaskDeleted(
    workspaceId: string,
    userId: string,
    taskId: string,
    details?: Prisma.JsonValue
  ): Promise<ActivityLog | null> {
    return this.logActivity({
      workspaceId,
      userId,
      action: ActivityAction.DELETED,
      entityType: EntityType.TASK,
      entityId: taskId,
      ...(details && { details }),
    });
  }

  /**
   * Log task completion
   */
  async logTaskCompleted(
    workspaceId: string,
    userId: string,
    taskId: string,
    details?: Prisma.JsonValue
  ): Promise<ActivityLog | null> {
    return this.logActivity({
      workspaceId,
      userId,
      action: ActivityAction.COMPLETED,
      entityType: EntityType.TASK,
      entityId: taskId,
      ...(details && { details }),
    });
  }

  /**
   * Log task assignment
   */
  async logTaskAssigned(
    workspaceId: string,
    userId: string,
    taskId: string,
    assigneeId: string
  ): Promise<ActivityLog | null> {
    return this.logActivity({
      workspaceId,
      userId,
      action: ActivityAction.ASSIGNED,
      entityType: EntityType.TASK,
      entityId: taskId,
      details: { assigneeId },
    });
  }

  /**
   * Log event creation
   */
  async logEventCreated(
    workspaceId: string,
    userId: string,
    eventId: string,
    details?: Prisma.JsonValue
  ): Promise<ActivityLog | null> {
    return this.logActivity({
      workspaceId,
      userId,
      action: ActivityAction.CREATED,
      entityType: EntityType.EVENT,
      entityId: eventId,
      ...(details && { details }),
    });
  }

  /**
   * Log event update
   */
  async logEventUpdated(
    workspaceId: string,
    userId: string,
    eventId: string,
    details?: Prisma.JsonValue
  ): Promise<ActivityLog | null> {
    return this.logActivity({
      workspaceId,
      userId,
      action: ActivityAction.UPDATED,
      entityType: EntityType.EVENT,
      entityId: eventId,
      ...(details && { details }),
    });
  }

  /**
   * Log event deletion
   */
  async logEventDeleted(
    workspaceId: string,
    userId: string,
    eventId: string,
    details?: Prisma.JsonValue
  ): Promise<ActivityLog | null> {
    return this.logActivity({
      workspaceId,
      userId,
      action: ActivityAction.DELETED,
      entityType: EntityType.EVENT,
      entityId: eventId,
      ...(details && { details }),
    });
  }

  /**
   * Log project creation
   */
  async logProjectCreated(
    workspaceId: string,
    userId: string,
    projectId: string,
    details?: Prisma.JsonValue
  ): Promise<ActivityLog | null> {
    return this.logActivity({
      workspaceId,
      userId,
      action: ActivityAction.CREATED,
      entityType: EntityType.PROJECT,
      entityId: projectId,
      ...(details && { details }),
    });
  }

  /**
   * Log project update
   */
  async logProjectUpdated(
    workspaceId: string,
    userId: string,
    projectId: string,
    details?: Prisma.JsonValue
  ): Promise<ActivityLog | null> {
    return this.logActivity({
      workspaceId,
      userId,
      action: ActivityAction.UPDATED,
      entityType: EntityType.PROJECT,
      entityId: projectId,
      ...(details && { details }),
    });
  }

  /**
   * Log project deletion
   */
  async logProjectDeleted(
    workspaceId: string,
    userId: string,
    projectId: string,
    details?: Prisma.JsonValue
  ): Promise<ActivityLog | null> {
    return this.logActivity({
      workspaceId,
      userId,
      action: ActivityAction.DELETED,
      entityType: EntityType.PROJECT,
      entityId: projectId,
      ...(details && { details }),
    });
  }

  /**
   * Log workspace creation
   */
  async logWorkspaceCreated(
    workspaceId: string,
    userId: string,
    details?: Prisma.JsonValue
  ): Promise<ActivityLog | null> {
    return this.logActivity({
      workspaceId,
      userId,
      action: ActivityAction.CREATED,
      entityType: EntityType.WORKSPACE,
      entityId: workspaceId,
      ...(details && { details }),
    });
  }

  /**
   * Log workspace update
   */
  async logWorkspaceUpdated(
    workspaceId: string,
    userId: string,
    details?: Prisma.JsonValue
  ): Promise<ActivityLog | null> {
    return this.logActivity({
      workspaceId,
      userId,
      action: ActivityAction.UPDATED,
      entityType: EntityType.WORKSPACE,
      entityId: workspaceId,
      ...(details && { details }),
    });
  }

  /**
   * Log workspace member added
   */
  async logWorkspaceMemberAdded(
    workspaceId: string,
    userId: string,
    memberId: string,
    role: string
  ): Promise<ActivityLog | null> {
    return this.logActivity({
      workspaceId,
      userId,
      action: ActivityAction.CREATED,
      entityType: EntityType.WORKSPACE,
      entityId: workspaceId,
      details: { memberId, role },
    });
  }

  /**
   * Log workspace member removed
   */
  async logWorkspaceMemberRemoved(
    workspaceId: string,
    userId: string,
    memberId: string
  ): Promise<ActivityLog | null> {
    return this.logActivity({
      workspaceId,
      userId,
      action: ActivityAction.DELETED,
      entityType: EntityType.WORKSPACE,
      entityId: workspaceId,
      details: { memberId },
    });
  }

  /**
   * Log user profile update
   */
  async logUserUpdated(
    workspaceId: string,
    userId: string,
    details?: Prisma.JsonValue
  ): Promise<ActivityLog | null> {
    return this.logActivity({
      workspaceId,
      userId,
      action: ActivityAction.UPDATED,
      entityType: EntityType.USER,
      entityId: userId,
      ...(details && { details }),
    });
  }

  /**
   * Log domain creation
   */
  async logDomainCreated(
    workspaceId: string,
    userId: string,
    domainId: string,
    details?: Prisma.JsonValue
  ): Promise<ActivityLog | null> {
    return this.logActivity({
      workspaceId,
      userId,
      action: ActivityAction.CREATED,
      entityType: EntityType.DOMAIN,
      entityId: domainId,
      ...(details && { details }),
    });
  }

  /**
   * Log domain update
   */
  async logDomainUpdated(
    workspaceId: string,
    userId: string,
    domainId: string,
    details?: Prisma.JsonValue
  ): Promise<ActivityLog | null> {
    return this.logActivity({
      workspaceId,
      userId,
      action: ActivityAction.UPDATED,
      entityType: EntityType.DOMAIN,
      entityId: domainId,
      ...(details && { details }),
    });
  }

  /**
   * Log domain deletion
   */
  async logDomainDeleted(
    workspaceId: string,
    userId: string,
    domainId: string,
    details?: Prisma.JsonValue
  ): Promise<ActivityLog | null> {
    return this.logActivity({
      workspaceId,
      userId,
      action: ActivityAction.DELETED,
      entityType: EntityType.DOMAIN,
      entityId: domainId,
      ...(details && { details }),
    });
  }

  /**
   * Log idea creation
   */
  async logIdeaCreated(
    workspaceId: string,
    userId: string,
    ideaId: string,
    details?: Prisma.JsonValue
  ): Promise<ActivityLog | null> {
    return this.logActivity({
      workspaceId,
      userId,
      action: ActivityAction.CREATED,
      entityType: EntityType.IDEA,
      entityId: ideaId,
      ...(details && { details }),
    });
  }

  /**
   * Log idea update
   */
  async logIdeaUpdated(
    workspaceId: string,
    userId: string,
    ideaId: string,
    details?: Prisma.JsonValue
  ): Promise<ActivityLog | null> {
    return this.logActivity({
      workspaceId,
      userId,
      action: ActivityAction.UPDATED,
      entityType: EntityType.IDEA,
      entityId: ideaId,
      ...(details && { details }),
    });
  }

  /**
   * Log idea deletion
   */
  async logIdeaDeleted(
    workspaceId: string,
    userId: string,
    ideaId: string,
    details?: Prisma.JsonValue
  ): Promise<ActivityLog | null> {
    return this.logActivity({
      workspaceId,
      userId,
      action: ActivityAction.DELETED,
      entityType: EntityType.IDEA,
      entityId: ideaId,
      ...(details && { details }),
    });
  }
}
