import { Inject, Injectable } from '@nestjs/common';
import { Prisma, WorkflowNodeInstance } from '@prisma/client';
import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
import { PrismaService } from 'nestjs-prisma';
import { Logger } from 'winston';

import { ConfigService } from '@nestjs/config';

@Injectable()
export class WorkflowNodeInstanceService {
  constructor(
    private prisma: PrismaService,
    private readonly config: ConfigService,
    @Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger,
  ) {}

  async createOne(
    workflowNodeInstanceCreateArgs: Prisma.WorkflowNodeInstanceCreateArgs,
  ) {
    return await this.prisma.workflowNodeInstance.create(
      workflowNodeInstanceCreateArgs,
    );
  }

  async createMany(data: Prisma.WorkflowNodeInstanceCreateManyArgs['data']) {
    return await this.prisma.workflowNodeInstance.createMany({
      data,
      skipDuplicates: true,
    });
  }

  async findMany(
    workflowNodeInstanceFindManyArgs: Prisma.WorkflowNodeInstanceFindManyArgs,
  ): Promise<{ itemCount: number; entities: WorkflowNodeInstance[] }> {
    const itemCount = await this.prisma.workflowNodeInstance.count({
      where: workflowNodeInstanceFindManyArgs.where,
    });
    const entities = await this.prisma.workflowNodeInstance.findMany(
      workflowNodeInstanceFindManyArgs,
    );
    return { itemCount, entities };
  }

  async findUnique(
    id: number,
    select: Prisma.WorkflowNodeInstanceFindUniqueArgs['select'],
  ) {
    return await this.prisma.workflowNodeInstance.findUnique({
      where: { id: id },
      select,
    });
  }

  async updateMany(
    workflowNodeInstanceUpdateManyArgs: Prisma.WorkflowNodeInstanceUpdateManyArgs,
  ) {
    return await this.prisma.workflowNodeInstance.updateMany(
      workflowNodeInstanceUpdateManyArgs,
    );
  }

  async updateUnique(
    id: number,
    data: Prisma.WorkflowNodeInstanceUpdateManyArgs['data'],
  ) {
    return await this.prisma.workflowNodeInstance.update({
      where: { id: id },
      data,
    });
  }

  async deleteMany(
    workflowNodeInstanceDeleteManyArgs: Prisma.WorkflowNodeInstanceDeleteManyArgs,
  ) {
    return await this.prisma.workflowNodeInstance.deleteMany(
      workflowNodeInstanceDeleteManyArgs,
    );
  }

  async deleteUnique(id: number) {
    await this.prisma.workflowNodeInstance.delete({
      where: { id: id },
    });
    return { count: 1 };
  }

  async count(
    workflowNodeInstanceCountArgs?: Prisma.WorkflowNodeInstanceCountArgs,
  ) {
    return await this.prisma.workflowNodeInstance.count(
      workflowNodeInstanceCountArgs,
    );
  }

  async groupBy(
    workflowNodeInstanceGroupByArgs: Prisma.WorkflowNodeInstanceGroupByArgs,
  ) {
    return await this.prisma.workflowNodeInstance.groupBy(
      workflowNodeInstanceGroupByArgs as any,
    );
  }

  async aggregate(
    workflowNodeInstanceAggregateArgs: Prisma.WorkflowNodeInstanceAggregateArgs,
  ) {
    return await this.prisma.workflowNodeInstance.aggregate(
      workflowNodeInstanceAggregateArgs,
    );
  }

  async findReferences(instanceId: number): Promise<
    {
      workflowId: string;
      workflowName: string;
      versionId: string;
      version: number;
      nodeId: string;
      nodeLabel: string;
    }[]
  > {
    // Get the latest version per workflow
    const workflows = await this.prisma.workflow.findMany({
      select: {
        id: true,
        name: true,
        versions: {
          orderBy: { version: 'desc' },
          take: 1,
          select: { id: true, version: true, dsl: true },
        },
      },
    });

    const results: {
      workflowId: string;
      workflowName: string;
      versionId: string;
      version: number;
      nodeId: string;
      nodeLabel: string;
    }[] = [];

    const targetId = String(instanceId);

    for (const wf of workflows) {
      const latestVersion = wf.versions[0];
      if (!latestVersion) continue;

      const dsl = latestVersion.dsl as any;
      if (!dsl?.nodes || !Array.isArray(dsl.nodes)) continue;

      for (const node of dsl.nodes) {
        if (node.instanceRef?.instanceId === targetId) {
          results.push({
            workflowId: String(wf.id),
            workflowName: wf.name,
            versionId: String(latestVersion.id),
            version: latestVersion.version,
            nodeId: node.id,
            nodeLabel: node.label || node.type,
          });
        }
      }
    }

    return results;
  }
}
