import { baseApi } from '../../base-api';
import type {
  AppNotification,
  ApplicationDetail,
  ApplicationKind,
  ApplicationPayment,
  ApplicationStaff,
  Attachment,
  InitiatePaymentResult,
  IssuedLicense,
  Inspection,
  LicenseApplication,
  LicenseCategoryDefinition,
  LicenseStatus,
  LicenseType,
  LicenseTypeRequirements,
  OperatorType,
  AssignableOfficer,
  DocumentDecision,
  DocumentReview,
  ExportResult,
  LicenseTemplate,
  Paginated,
  QueueCounts,
  QueueFilter,
  RemarkTargetType,
  SavedQueueView,
  TemplateFieldPlacement,
  TemplateLogoPlacement,
  TemplatePageOptions,
  TemplateVariable,
} from './licensing.types';

/**
 * Drops empty filters and flattens the status array.
 *
 * The grid keeps every facet in one object and serialises it to the URL, so
 * cleared facets arrive as undefined/[]; sending those verbatim would put
 * `status=` and `assignee=` on the wire and fail DTO validation.
 */
function serialiseQueueFilter(
  filter: QueueFilter | void,
): Record<string, unknown> {
  if (!filter) return {};
  const params: Record<string, unknown> = {};
  for (const [key, value] of Object.entries(filter)) {
    if (value === undefined || value === null || value === '') continue;
    if (Array.isArray(value)) {
      if (value.length === 0) continue;
      params[key] = value.join(',');
      continue;
    }
    params[key] = value;
  }
  return params;
}

const TAGS = [
  'LicenseType',
  'OperatorType',
  'LicenseApplication',
  'ApplicationQueue',
  'Attachment',
  'Notification',
  'Inspection',
  'License',
  'SavedView',
  'LicenseTemplate',
] as const;

const listTag = (type: (typeof TAGS)[number]) => ({ type, id: 'LIST' }) as const;
const itemTag = (type: (typeof TAGS)[number], id: string) => ({ type, id }) as const;

/**
 * Typed licensing endpoints, shared by the portal and the backoffice.
 *
 * Each resource gets its own cache tag so a transition invalidates the one
 * application and its queue, rather than the whole store.
 */
export const licensingApi = baseApi
  .enhanceEndpoints({ addTagTypes: TAGS })
  .injectEndpoints({
    endpoints: (builder) => ({
      // ------------------------------------------------------------- config
      /** Active licence types an applicant can choose from. */
      getLicenseTypes: builder.query<Paginated<LicenseType>, void>({
        query: () => ({ url: '/license-types' }),
        providesTags: () => [listTag('LicenseType')],
      }),

      /**
       * The signed-in applicant's declared modes of operation.
       *
       * Separate from the licence-type catalogue on purpose: the catalogue is
       * the same for everyone and heavily cached, while this is per-user and
       * changes the moment they edit their profile.
       */
      getMyOperatorTypes: builder.query<{ items: OperatorType[] }, void>({
        query: () => ({ url: '/profiles/me/operations' }),
        providesTags: () => [listTag('OperatorType')],
      }),

      /** Replaces the set — see the Operations tab in the portal profile. */
      updateMyOperatorTypes: builder.mutation<
        { items: OperatorType[] },
        { licenseTypeIds: string[] }
      >({
        query: (body) => ({
          url: '/profiles/me/operations',
          method: 'PUT',
          body,
        }),
        // The catalogue is filtered by this, so it has to refetch too.
        invalidatesTags: (_r, error) =>
          error ? [] : [listTag('OperatorType'), listTag('LicenseType')],
      }),

      /**
       * Category catalogue used to group the licence cards. Static on the
       * server, so it is cached under the licence-type list tag.
       */
      getLicenseCategories: builder.query<
        Paginated<LicenseCategoryDefinition>,
        void
      >({
        query: () => ({ url: '/license-categories' }),
        providesTags: () => [listTag('LicenseType')],
      }),

      /**
       * Fee configuration, for licensing administrators.
       *
       * `null` is a meaningful value for both amounts and must survive the
       * round trip: null on the new-application fee means the licence is free,
       * null on the renewal fee means it is charged at the new-application
       * rate. Sending `undefined` instead would leave the column untouched.
       */
      updateLicenseFees: builder.mutation<
        LicenseType,
        {
          id: string;
          feeNewApplication?: number | null;
          feeRenewal?: number | null;
          feeCurrency?: string;
        }
      >({
        query: ({ id, ...body }) => ({
          url: `/license-types/${id}/fees`,
          method: 'PATCH',
          body,
        }),
        invalidatesTags: (_r, error, { id }) =>
          error ? [] : [listTag('LicenseType'), itemTag('LicenseType', id)],
      }),

      /** Validity is edited beside the certificate design, not with the fees. */
      updateLicenseValidity: builder.mutation<
        LicenseType,
        { id: string; validityMonths: number }
      >({
        query: ({ id, validityMonths }) => ({
          url: `/license-types/${id}/validity`,
          method: 'PATCH',
          body: { validityMonths },
        }),
        invalidatesTags: (_r, error, { id }) =>
          error ? [] : [itemTag('LicenseType', id), listTag('LicenseType')],
      }),

      getLicenseTypeRequirements: builder.query<
        LicenseTypeRequirements,
        { idOrKey: string; kind?: ApplicationKind }
      >({
        query: ({ idOrKey, kind = 'NEW' }) => ({
          url: `/license-types/requirements/${idOrKey}`,
          params: { kind },
        }),
        providesTags: (_r, _e, arg) => [itemTag('LicenseType', arg.idOrKey)],
      }),

      // -------------------------------------------------------- application
      createApplication: builder.mutation<
        LicenseApplication,
        { licenseType: string; kind?: ApplicationKind; previousLicenseId?: string }
      >({
        query: (body) => ({ url: '/license-applications', method: 'POST', body }),
        invalidatesTags: (_r, error) => (error ? [] : [listTag('LicenseApplication')]),
      }),

      getMyApplications: builder.query<Paginated<LicenseApplication>, void>({
        query: () => ({ url: '/license-applications/mine' }),
        providesTags: () => [listTag('LicenseApplication')],
      }),

      getApplication: builder.query<ApplicationDetail, string>({
        query: (id) => ({ url: `/license-applications/${id}` }),
        providesTags: (_r, _e, id) => [itemTag('LicenseApplication', id)],
      }),

      patchSection: builder.mutation<
        LicenseApplication,
        { id: string; sectionKey: string; values: Record<string, unknown> }
      >({
        query: ({ id, sectionKey, values }) => ({
          url: `/license-applications/${id}/sections/${sectionKey}`,
          method: 'PATCH',
          body: { values },
        }),
        invalidatesTags: (_r, error, { id }) =>
          error ? [] : [itemTag('LicenseApplication', id)],
      }),

      addStaff: builder.mutation<
        ApplicationStaff,
        { id: string; roleKey: string; fullName: string; position?: string; yearsOfExperience?: number }
      >({
        query: ({ id, ...body }) => ({
          url: `/license-applications/${id}/staff`,
          method: 'POST',
          body,
        }),
        invalidatesTags: (_r, error, { id }) =>
          error ? [] : [itemTag('LicenseApplication', id)],
      }),

      removeStaff: builder.mutation<unknown, { id: string; staffId: string }>({
        query: ({ id, staffId }) => ({
          url: `/license-applications/${id}/staff/${staffId}`,
          method: 'DELETE',
        }),
        invalidatesTags: (_r, error, { id }) =>
          error ? [] : [itemTag('LicenseApplication', id)],
      }),

      submitApplication: builder.mutation<LicenseApplication, string>({
        query: (id) => ({ url: `/license-applications/${id}/submit`, method: 'POST' }),
        invalidatesTags: (_r, error, id) =>
          error ? [] : [itemTag('LicenseApplication', id), listTag('LicenseApplication'), listTag('ApplicationQueue')],
      }),

      resolveRemark: builder.mutation<unknown, { id: string; remarkId: string }>({
        query: ({ id, remarkId }) => ({
          url: `/license-applications/${id}/remarks/${remarkId}/resolve`,
          method: 'PATCH',
        }),
        invalidatesTags: (_r, error, { id }) =>
          error ? [] : [itemTag('LicenseApplication', id)],
      }),

      resubmitApplication: builder.mutation<LicenseApplication, string>({
        query: (id) => ({ url: `/license-applications/${id}/resubmit`, method: 'POST' }),
        invalidatesTags: (_r, error, id) =>
          error ? [] : [itemTag('LicenseApplication', id), listTag('LicenseApplication')],
      }),

      // -------------------------------------------------------- attachments
      getAttachments: builder.query<Attachment[], { ownerType: string; ownerId: string }>({
        query: ({ ownerType, ownerId }) => ({
          url: '/attachments',
          params: { ownerType, ownerId, withUrls: true },
        }),
        providesTags: (_r, _e, arg) => [itemTag('Attachment', arg.ownerId)],
      }),

      deleteAttachment: builder.mutation<unknown, { attachmentId: string; ownerId: string }>({
        query: ({ attachmentId }) => ({
          url: `/attachments/${attachmentId}`,
          method: 'DELETE',
        }),
        invalidatesTags: (_r, error, { ownerId }) =>
          error ? [] : [itemTag('Attachment', ownerId)],
      }),

      // ----------------------------------------------------------- payments
      initiatePayment: builder.mutation<
        InitiatePaymentResult,
        { id: string; provider?: string; platform?: 'web' | 'mobile'; payerAccount?: string }
      >({
        query: ({ id, ...body }) => ({
          url: `/license-applications/${id}/payments/initiate`,
          method: 'POST',
          body,
        }),
        invalidatesTags: (_r, error, { id }) =>
          error ? [] : [itemTag('LicenseApplication', id)],
      }),

      getApplicationPayment: builder.query<ApplicationPayment, string>({
        query: (id) => ({ url: `/license-applications/${id}/payments` }),
        providesTags: (_r, _e, id) => [itemTag('LicenseApplication', id)],
      }),

      /** Testing shortcut — only offered when the API reports it enabled. */
      bypassPayment: builder.mutation<
        { status: LicenseStatus; certificateIssued: boolean },
        string
      >({
        query: (id) => ({
          url: `/license-applications/${id}/payments/bypass`,
          method: 'POST',
        }),
        invalidatesTags: (_r, error, id) =>
          error
            ? []
            : [itemTag('LicenseApplication', id), listTag('LicenseApplication'), listTag('License')],
      }),

      getPaymentCapabilities: builder.query<{ bypassEnabled: boolean }, void>({
        query: () => ({ url: '/license-applications/payments/capabilities' }),
      }),

      // ------------------------------------------------------------ licences
      /** The licence register for enforcement officers. */
      getLicenses: builder.query<
        Paginated<IssuedLicense>,
        { search?: string } | void
      >({
        query: (args) => ({
          url: '/licenses',
          params: args?.search ? { search: args.search } : undefined,
        }),
        providesTags: () => [listTag('License')],
      }),

      getMyLicenses: builder.query<Paginated<IssuedLicense>, void>({
        query: () => ({ url: '/licenses/mine' }),
        providesTags: () => [listTag('License')],
      }),

      suspendLicense: builder.mutation<IssuedLicense, { id: string; reason: string }>({
        query: ({ id, reason }) => ({
          url: `/licenses/${id}/suspend`,
          method: 'POST',
          body: { reason },
        }),
        invalidatesTags: (_r, error, { id }) =>
          error ? [] : [itemTag('License', id), listTag('License')],
      }),

      revokeLicense: builder.mutation<IssuedLicense, { id: string; reason: string }>({
        query: ({ id, reason }) => ({
          url: `/licenses/${id}/revoke`,
          method: 'POST',
          body: { reason },
        }),
        invalidatesTags: (_r, error, { id }) =>
          error ? [] : [itemTag('License', id), listTag('License')],
      }),

      reinstateLicense: builder.mutation<IssuedLicense, { id: string; reason: string }>({
        query: ({ id, reason }) => ({
          url: `/licenses/${id}/reinstate`,
          method: 'POST',
          body: { reason },
        }),
        invalidatesTags: (_r, error, { id }) =>
          error ? [] : [itemTag('License', id), listTag('License')],
      }),

      getCertificateUrl: builder.mutation<{ url: string }, string>({
        query: (id) => ({ url: `/licenses/${id}/certificate` }),
      }),

      // ------------------------------------------------------------- review
      getQueue: builder.query<Paginated<LicenseApplication>, QueueFilter | void>({
        query: (params) => ({
          url: '/license-application-review/queue',
          params: serialiseQueueFilter(params),
        }),
        providesTags: () => [listTag('ApplicationQueue')],
      }),

      getAssignedToMe: builder.query<
        Paginated<LicenseApplication>,
        QueueFilter | void
      >({
        query: (params) => ({
          url: '/license-application-review/assigned-to-me',
          params: serialiseQueueFilter(params),
        }),
        providesTags: () => [listTag('ApplicationQueue')],
      }),

      /** Every non-draft application — backs the grid's "All" view. */
      getAllApplications: builder.query<
        Paginated<LicenseApplication>,
        QueueFilter | void
      >({
        query: (params) => ({
          url: '/license-application-review/all',
          params: serialiseQueueFilter(params),
        }),
        providesTags: () => [listTag('ApplicationQueue')],
      }),

      /**
       * Counts for the saved-view tabs. Shares the ApplicationQueue tag, so a
       * claim or a decision refreshes the badges along with the list and the
       * numbers can never drift from what the grid is showing.
       */
      getQueueCounts: builder.query<QueueCounts, string | void>({
        query: (licenseTypeKey) => ({
          url: '/license-application-review/counts',
          params: licenseTypeKey ? { licenseTypeKey } : undefined,
        }),
        providesTags: () => [listTag('ApplicationQueue')],
      }),

      getApplicationForReview: builder.query<ApplicationDetail, string>({
        query: (id) => ({ url: `/license-application-review/${id}` }),
        providesTags: (_r, _e, id) => [itemTag('LicenseApplication', id)],
      }),

      claimApplication: builder.mutation<LicenseApplication, string>({
        query: (id) => ({ url: `/license-application-review/${id}/claim`, method: 'POST' }),
        invalidatesTags: (_r, error, id) =>
          error ? [] : [itemTag('LicenseApplication', id), listTag('ApplicationQueue')],
      }),

      completeReview: builder.mutation<
        LicenseApplication,
        { id: string; capitalAmountVerified?: number; remark?: string }
      >({
        query: ({ id, ...body }) => ({
          url: `/license-application-review/${id}/complete-review`,
          method: 'POST',
          body,
        }),
        invalidatesTags: (_r, error, { id }) =>
          error ? [] : [itemTag('LicenseApplication', id), listTag('ApplicationQueue')],
      }),

      requestAdjustment: builder.mutation<
        LicenseApplication,
        {
          id: string;
          generalRemark?: string;
          items: { targetType: RemarkTargetType; targetKey: string; remark: string }[];
          /** Officer-edited wording for the applicant notification. */
          notificationBody?: string;
        }
      >({
        query: ({ id, ...body }) => ({
          url: `/license-application-review/${id}/request-adjustment`,
          method: 'POST',
          body,
        }),
        invalidatesTags: (_r, error, { id }) =>
          error ? [] : [itemTag('LicenseApplication', id), listTag('ApplicationQueue')],
      }),

      approveDocuments: builder.mutation<LicenseApplication, { id: string; remark?: string }>({
        query: ({ id, ...body }) => ({
          url: `/license-application-review/${id}/approve-documents`,
          method: 'POST',
          body,
        }),
        invalidatesTags: (_r, error, { id }) =>
          error ? [] : [itemTag('LicenseApplication', id), listTag('ApplicationQueue')],
      }),

      /**
       * `capitalAmountVerified` is what the officer confirms against the bank
       * letter. Licence types with a capital threshold reject the approval
       * without it, so it is part of the contract, not an optional extra.
       */
      finalApprove: builder.mutation<
        LicenseApplication,
        { id: string; remark?: string; capitalAmountVerified?: number }
      >({
        query: ({ id, ...body }) => ({
          url: `/license-application-review/${id}/final-approve`,
          method: 'POST',
          body,
        }),
        invalidatesTags: (_r, error, { id }) =>
          error ? [] : [itemTag('LicenseApplication', id), listTag('ApplicationQueue')],
      }),

      rejectApplication: builder.mutation<
        LicenseApplication,
        { id: string; reason: string; notificationBody?: string }
      >({
        query: ({ id, ...body }) => ({
          url: `/license-application-review/${id}/reject`,
          method: 'POST',
          body,
        }),
        invalidatesTags: (_r, error, { id }) =>
          error ? [] : [itemTag('LicenseApplication', id), listTag('ApplicationQueue')],
      }),

      /** Places a candidate who has paid the examination fee into a sitting. */
      scheduleExam: builder.mutation<
        LicenseApplication,
        { id: string; examId: string; admissionNumber?: string; examDate?: string }
      >({
        query: ({ id, ...body }) => ({
          url: `/license-application-review/${id}/schedule-exam`,
          method: 'POST',
          body,
        }),
        invalidatesTags: (_r, error, { id }) =>
          error ? [] : [itemTag('LicenseApplication', id), listTag('ApplicationQueue')],
      }),

      /**
       * Raises the examination fee — after eligibility approval, or again when
       * a failed candidate elects to resit.
       */
      requestExamPayment: builder.mutation<LicenseApplication, string>({
        query: (id) => ({
          url: `/license-applications/${id}/request-exam-payment`,
          method: 'POST',
        }),
        invalidatesTags: (_r, error, id) =>
          error ? [] : [itemTag('LicenseApplication', id), listTag('LicenseApplication')],
      }),

      // ------------------------------------------------- certificate designs
      getLicenseTemplates: builder.query<LicenseTemplate[], string | void>({
        query: (licenseTypeId) => ({
          url: '/license-templates',
          params: licenseTypeId ? { licenseTypeId } : {},
        }),
        providesTags: () => [listTag('LicenseTemplate')],
      }),

      getTemplateVariables: builder.query<TemplateVariable[], void>({
        query: () => ({ url: '/license-templates/variables' }),
      }),

      getBuiltInTemplate: builder.query<{ hbsSource: string }, void>({
        query: () => ({ url: '/license-templates/built-in' }),
      }),

      createLicenseTemplate: builder.mutation<
        LicenseTemplate,
        {
          licenseTypeId: string;
          name: string;
          hbsSource?: string;
          pageOptions?: TemplatePageOptions;
        }
      >({
        query: (body) => ({ url: '/license-templates', method: 'POST', body }),
        invalidatesTags: (_r, error) => (error ? [] : [listTag('LicenseTemplate')]),
      }),

      updateLicenseTemplate: builder.mutation<
        LicenseTemplate,
        {
          id: string;
          name?: string;
          hbsSource?: string;
          pageOptions?: TemplatePageOptions;
          backgroundUrl?: string;
          logoUrl?: string;
          logoPlacement?: TemplateLogoPlacement;
          fieldPlacements?: TemplateFieldPlacement[];
        }
      >({
        query: ({ id, ...body }) => ({
          url: `/license-templates/${id}`,
          method: 'PATCH',
          body,
        }),
        invalidatesTags: (_r, error) => (error ? [] : [listTag('LicenseTemplate')]),
      }),

      publishLicenseTemplate: builder.mutation<LicenseTemplate, string>({
        query: (id) => ({ url: `/license-templates/${id}/publish`, method: 'POST' }),
        // The previously published design is archived by the same call, so the
        // whole list is refetched rather than patching two rows by hand.
        invalidatesTags: (_r, error) => (error ? [] : [listTag('LicenseTemplate')]),
      }),

      archiveLicenseTemplate: builder.mutation<LicenseTemplate, string>({
        query: (id) => ({ url: `/license-templates/${id}/archive`, method: 'POST' }),
        invalidatesTags: (_r, error) => (error ? [] : [listTag('LicenseTemplate')]),
      }),

      deleteLicenseTemplate: builder.mutation<unknown, string>({
        query: (id) => ({ url: `/license-templates/${id}`, method: 'DELETE' }),
        invalidatesTags: (_r, error) => (error ? [] : [listTag('LicenseTemplate')]),
      }),

      // ------------------------------------------------------ document review
      getDocumentReviews: builder.query<DocumentReview[], string>({
        query: (id) => ({ url: `/license-application-review/${id}/document-reviews` }),
        providesTags: (_r, _e, id) => [itemTag('LicenseApplication', id)],
      }),

      reviewDocument: builder.mutation<
        DocumentReview,
        {
          id: string;
          documentKey: string;
          decision: DocumentDecision;
          reason?: string;
          attachmentId?: string;
        }
      >({
        query: ({ id, documentKey, ...body }) => ({
          url: `/license-application-review/${id}/documents/${encodeURIComponent(documentKey)}/review`,
          method: 'POST',
          body,
        }),
        invalidatesTags: (_r, error, { id }) =>
          error ? [] : [itemTag('LicenseApplication', id)],
      }),

      clearDocumentReview: builder.mutation<unknown, { id: string; documentKey: string }>({
        query: ({ id, documentKey }) => ({
          url: `/license-application-review/${id}/documents/${encodeURIComponent(documentKey)}/review`,
          method: 'DELETE',
        }),
        invalidatesTags: (_r, error, { id }) =>
          error ? [] : [itemTag('LicenseApplication', id)],
      }),

      // ----------------------------------------------------------- saved views
      getSavedViews: builder.query<SavedQueueView[], void>({
        query: () => ({ url: '/license-application-review/saved-views' }),
        providesTags: () => [listTag('SavedView')],
      }),

      createSavedView: builder.mutation<
        SavedQueueView,
        { name: string; queryString: string; isShared?: boolean; isDefault?: boolean }
      >({
        query: (body) => ({
          url: '/license-application-review/saved-views',
          method: 'POST',
          body,
        }),
        invalidatesTags: (_r, error) => (error ? [] : [listTag('SavedView')]),
      }),

      deleteSavedView: builder.mutation<unknown, string>({
        query: (viewId) => ({
          url: `/license-application-review/saved-views/${viewId}`,
          method: 'DELETE',
        }),
        invalidatesTags: (_r, error) => (error ? [] : [listTag('SavedView')]),
      }),

      // ------------------------------------------------------------- export
      /**
       * The whole filtered result set, not the current page. Lazy so it only
       * runs when the officer actually asks for a file.
       */
      exportApplications: builder.query<ExportResult, QueueFilter | void>({
        query: (params) => ({
          url: '/license-application-review/export',
          params: serialiseQueueFilter(params),
        }),
      }),

      /** Officers the Assign and Escalate dialogs can offer. */
      getAssignableOfficers: builder.query<AssignableOfficer[], void>({
        query: () => ({ url: '/license-application-review/officers' }),
      }),

      // ----------------------------------------------------- workflow controls
      assignApplication: builder.mutation<
        LicenseApplication,
        { id: string; officerId: string; remark?: string }
      >({
        query: ({ id, ...body }) => ({
          url: `/license-application-review/${id}/assign`,
          method: 'POST',
          body,
        }),
        invalidatesTags: (_r, error, { id }) =>
          error ? [] : [itemTag('LicenseApplication', id), listTag('ApplicationQueue')],
      }),

      holdApplication: builder.mutation<
        LicenseApplication,
        { id: string; reason: string }
      >({
        query: ({ id, reason }) => ({
          url: `/license-application-review/${id}/hold`,
          method: 'POST',
          body: { reason },
        }),
        invalidatesTags: (_r, error, { id }) =>
          error ? [] : [itemTag('LicenseApplication', id), listTag('ApplicationQueue')],
      }),

      resumeApplication: builder.mutation<
        LicenseApplication,
        { id: string; remark?: string }
      >({
        query: ({ id, remark }) => ({
          url: `/license-application-review/${id}/resume`,
          method: 'POST',
          body: { remark },
        }),
        invalidatesTags: (_r, error, { id }) =>
          error ? [] : [itemTag('LicenseApplication', id), listTag('ApplicationQueue')],
      }),

      escalateApplication: builder.mutation<
        LicenseApplication,
        { id: string; supervisorId: string; reason: string }
      >({
        query: ({ id, ...body }) => ({
          url: `/license-application-review/${id}/escalate`,
          method: 'POST',
          body,
        }),
        invalidatesTags: (_r, error, { id }) =>
          error ? [] : [itemTag('LicenseApplication', id), listTag('ApplicationQueue')],
      }),

      confirmPayment: builder.mutation<LicenseApplication, string>({
        query: (id) => ({
          url: `/license-application-review/${id}/confirm-payment`,
          method: 'POST',
        }),
        invalidatesTags: (_r, error, id) =>
          error ? [] : [itemTag('LicenseApplication', id), listTag('ApplicationQueue')],
      }),

      // --------------------------------------------------------- inspection
      scheduleInspection: builder.mutation<
        Inspection,
        { applicationId: string; scheduledDate: string; location?: string }
      >({
        query: (body) => ({ url: '/inspections', method: 'POST', body }),
        invalidatesTags: (_r, error, { applicationId }) =>
          error ? [] : [itemTag('LicenseApplication', applicationId), listTag('Inspection')],
      }),

      getInspections: builder.query<Inspection[], string>({
        query: (applicationId) => ({ url: `/inspections/application/${applicationId}` }),
        providesTags: () => [listTag('Inspection')],
      }),

      recordInspectionResult: builder.mutation<
        Inspection,
        {
          inspectionId: string;
          applicationId: string;
          result: 'PASSED' | 'FAILED';
          findings: string;
          /** Structured per-item outcomes (office, warehouse, vehicles, …). */
          checklist?: {
            key: string;
            label: string;
            outcome: 'PASS' | 'FAIL' | 'NEEDS_CORRECTION';
            note?: string;
          }[];
        }
      >({
        query: ({ inspectionId, result, findings, checklist }) => ({
          url: `/inspections/${inspectionId}/result`,
          method: 'PATCH',
          body: { result, findings, ...(checklist?.length ? { checklist } : {}) },
        }),
        invalidatesTags: (_r, error, { applicationId }) =>
          error ? [] : [itemTag('LicenseApplication', applicationId), listTag('Inspection')],
      }),

      // ------------------------------------------------------ notifications
      getNotifications: builder.query<{ count: number; items: AppNotification[] }, void>({
        query: () => ({ url: '/notifications' }),
        providesTags: () => [listTag('Notification')],
      }),

      getUnseenNotifications: builder.query<{ count: number; items: AppNotification[] }, void>({
        query: () => ({ url: '/notifications/unseen' }),
        providesTags: () => [listTag('Notification')],
      }),

      markNotificationRead: builder.mutation<unknown, string>({
        query: (id) => ({ url: `/notifications/${id}/read`, method: 'PATCH' }),
        invalidatesTags: (_r, error) => (error ? [] : [listTag('Notification')]),
      }),
    }),
    overrideExisting: false,
  });

export const {
  useGetLicenseTypesQuery,
  useGetLicenseCategoriesQuery,
  useUpdateLicenseFeesMutation,
  useUpdateLicenseValidityMutation,
  useGetLicenseTypeRequirementsQuery,
  useCreateApplicationMutation,
  useGetMyApplicationsQuery,
  useGetApplicationQuery,
  useInitiatePaymentMutation,
  useBypassPaymentMutation,
  useGetPaymentCapabilitiesQuery,
  useGetMyLicensesQuery,
  useGetLicensesQuery,
  useGetCertificateUrlMutation,
  useGetApplicationPaymentQuery,
  usePatchSectionMutation,
  useAddStaffMutation,
  useRemoveStaffMutation,
  useSubmitApplicationMutation,
  useResolveRemarkMutation,
  useResubmitApplicationMutation,
  useGetAttachmentsQuery,
  useDeleteAttachmentMutation,
  useGetQueueQuery,
  useGetAssignedToMeQuery,
  useGetAllApplicationsQuery,
  useGetQueueCountsQuery,
  useGetLicenseTemplatesQuery,
  useGetTemplateVariablesQuery,
  useGetBuiltInTemplateQuery,
  useCreateLicenseTemplateMutation,
  useUpdateLicenseTemplateMutation,
  usePublishLicenseTemplateMutation,
  useArchiveLicenseTemplateMutation,
  useDeleteLicenseTemplateMutation,
  useGetDocumentReviewsQuery,
  useReviewDocumentMutation,
  useClearDocumentReviewMutation,
  useGetSavedViewsQuery,
  useCreateSavedViewMutation,
  useDeleteSavedViewMutation,
  useLazyExportApplicationsQuery,
  useGetAssignableOfficersQuery,
  useSuspendLicenseMutation,
  useRevokeLicenseMutation,
  useReinstateLicenseMutation,
  useAssignApplicationMutation,
  useHoldApplicationMutation,
  useResumeApplicationMutation,
  useEscalateApplicationMutation,
  useGetApplicationForReviewQuery,
  useClaimApplicationMutation,
  useCompleteReviewMutation,
  useRequestAdjustmentMutation,
  useApproveDocumentsMutation,
  useFinalApproveMutation,
  useRejectApplicationMutation,
  useScheduleExamMutation,
  useRequestExamPaymentMutation,
  useConfirmPaymentMutation,
  useScheduleInspectionMutation,
  useGetInspectionsQuery,
  useRecordInspectionResultMutation,
  useGetNotificationsQuery,
  useGetUnseenNotificationsQuery,
  useMarkNotificationReadMutation,
  useGetMyOperatorTypesQuery,
  useUpdateMyOperatorTypesMutation,
} = licensingApi;
