import { Injectable } from '@nestjs/common';

import { Prisma } from '@/generated/prisma/client';
import { PrismaService } from '@/prisma/prisma.service';

const issueMatrixSelect = {
  id: true,
  issueId: true,
  meetingSummaryId: true,
  rgcDecision: true,
  nextStep: true,
  remark: true,
  meetingSummary: {
    select: {
      updatedAt: true,
    },
  },
  issueStatus: {
    select: {
      id: true,
      code: true,
      name: true,
    },
  },
  issue: {
    select: {
      id: true,
      title: true,
      description: true,
      recommendation: true,
      escalation: true,
      category: {
        select: {
          id: true,
          name: true,
        },
      },
      issueStatus: {
        select: {
          id: true,
          code: true,
          name: true,
        },
      },
      stakeholder: {
        select: {
          id: true,
          name: true,
        },
      },
      governmentAgencies: {
        where: {
          stakeholder: {
            deletedAt: null,
          },
        },
        orderBy: {
          agencyOrder: 'asc',
        },
        select: {
          agencyOrder: true,
          stakeholder: {
            select: {
              id: true,
              name: true,
              logo: true,
            },
          },
        },
      },
    },
  },
} as const satisfies Prisma.IssueResolvesSelect;

export type SubmittedIssueResolve = Prisma.IssueResolvesGetPayload<{
  select: typeof issueMatrixSelect;
}>;

@Injectable()
export class IssuesRepository {
  constructor(private readonly prisma: PrismaService) {}

  /**
   * Return submitted CDC escalations newest first. The service keeps only the
   * first row for each issue, which makes the latest submission authoritative.
   */
  findSubmittedIssueResolves(
    escalateName: string,
  ): Promise<SubmittedIssueResolve[]> {
    return this.prisma.issueResolves.findMany({
      where: {
        deletedAt: null,
        escalate: {
          is: {
            name: {
              equals: escalateName,
              mode: 'insensitive',
            },
            deletedAt: null,
          },
        },
        meetingSummary: {
          deletedAt: null,
          meetingSummaryStatus: {
            code: 'SUBMITTED',
            deletedAt: null,
          },
          user: {
            deletedAt: null,
            roles: {
              some: {
                role: {
                  name: 'ministry',
                  deletedAt: null,
                },
              },
            },
          },
        },
        issueStatus: {
          is: {
            deletedAt: null,
          },
        },
        issue: {
          deletedAt: null,
          category: {
            deletedAt: null,
          },
          issueStatus: {
            deletedAt: null,
          },
          stakeholder: {
            deletedAt: null,
          },
        },
      },
      select: issueMatrixSelect,
      orderBy: [
        {
          meetingSummary: {
            updatedAt: 'desc',
          },
        },
        {
          updatedAt: 'desc',
        },
        {
          id: 'desc',
        },
      ],
    });
  }

  /**
   * Carry a CDC row edit over to the meeting-summary resolution.
   *
   * Two reasons this is needed for ministry-submitted rows:
   * - the matrix reads their status from the resolution first, so writing only
   *   the issue's own status would leave the table unchanged;
   * - the meeting summary prefers its own agency overrides for slots 2..N, so
   *   they have to be cleared or the old ministries reappear there.
   */
  /** Flag the issue for the plenary, or take the flag off. */
  async setIssueEscalation(
    issueId: number,
    escalation: boolean,
  ): Promise<void> {
    await this.prisma.issues.update({
      where: { id: issueId },
      data: { escalation },
    });
  }

  async applyResolveOverrides(
    issueResolveId: number,
    changes: { issueStatusId?: number; clearAgencies: boolean },
  ): Promise<void> {
    await this.prisma.$transaction(async (transaction) => {
      if (changes.issueStatusId !== undefined) {
        // updateMany so a soft-deleted resolution is skipped instead of throwing.
        await transaction.issueResolves.updateMany({
          where: {
            id: issueResolveId,
            deletedAt: null,
          },
          data: {
            issueStatusId: changes.issueStatusId,
          },
        });
      }

      if (changes.clearAgencies) {
        await transaction.issueResolveAgencies.deleteMany({
          where: {
            issueResolveId,
          },
        });
      }
    });
  }
}
