import { type EmptyFields } from "@tailor-platform/erp-kit/core";
import { type TailorAnyDBField } from "@tailor-platform/sdk";
import type { defineModule as defineUserManagementModule } from "../user-management";
import { activateApprovalPolicy } from "./command/activateApprovalPolicy.generated";
import { approveApprovalStep } from "./command/approveApprovalStep.generated";
import { cancelApprovalRequest } from "./command/cancelApprovalRequest.generated";
import { createApprovalPolicy } from "./command/createApprovalPolicy.generated";
import { createApprovalRequest } from "./command/createApprovalRequest.generated";
import { deactivateApprovalPolicy } from "./command/deactivateApprovalPolicy.generated";
import { delegateApprovalStep } from "./command/delegateApprovalStep.generated";
import { rejectApprovalStep } from "./command/rejectApprovalStep.generated";
import { updateApprovalPolicy } from "./command/updateApprovalPolicy.generated";
import { withdrawApprovalRequest } from "./command/withdrawApprovalRequest.generated";
import {
  createApprovalDecisionType,
  type CreateApprovalDecisionTypeParams,
} from "./db/approvalDecision";
import { createApprovalPolicyType, type CreateApprovalPolicyTypeParams } from "./db/approvalPolicy";
import {
  createApprovalPolicyStepType,
  type CreateApprovalPolicyStepTypeParams,
} from "./db/approvalPolicyStep";
import {
  createApprovalPolicyStepAssigneeType,
  type CreateApprovalPolicyStepAssigneeTypeParams,
} from "./db/approvalPolicyStepAssignee";
import {
  createApprovalRequestType,
  type CreateApprovalRequestTypeParams,
} from "./db/approvalRequest";
import { createApprovalStepType, type CreateApprovalStepTypeParams } from "./db/approvalStep";
import {
  createApprovalStepAssigneeType,
  type CreateApprovalStepAssigneeTypeParams,
} from "./db/approvalStepAssignee";
import { getActiveApprovalRequest } from "./query/getActiveApprovalRequest.generated";
import { getApprovalDecisionHistory } from "./query/getApprovalDecisionHistory.generated";
import { listApprovalPolicies } from "./query/listApprovalPolicies.generated";
import { listApprovalRequestsByTarget } from "./query/listApprovalRequestsByTarget.generated";
import { listApprovalRequestsForApprover } from "./query/listApprovalRequestsForApprover.generated";

type UserManagementModule = ReturnType<typeof defineUserManagementModule>;
type UserManagementDB = UserManagementModule["db"];
export type UserManagementQueries = UserManagementModule["queries"];

export interface DefineModuleParams<
  PF extends Record<string, TailorAnyDBField>,
  PSF extends Record<string, TailorAnyDBField>,
  PSAF extends Record<string, TailorAnyDBField>,
  RF extends Record<string, TailorAnyDBField>,
  SF extends Record<string, TailorAnyDBField>,
  SAF extends Record<string, TailorAnyDBField>,
  DF extends Record<string, TailorAnyDBField>,
> {
  approvalPolicy?: CreateApprovalPolicyTypeParams<PF>;
  approvalPolicyStep?: CreateApprovalPolicyStepTypeParams<PSF>;
  approvalPolicyStepAssignee?: Omit<
    CreateApprovalPolicyStepAssigneeTypeParams<PSAF>,
    "userType" | "roleType"
  >;
  approvalRequest?: Omit<CreateApprovalRequestTypeParams<RF>, "userType">;
  approvalStep?: CreateApprovalStepTypeParams<SF>;
  approvalStepAssignee?: Omit<CreateApprovalStepAssigneeTypeParams<SAF>, "userType" | "roleType">;
  approvalDecision?: Omit<CreateApprovalDecisionTypeParams<DF>, "userType">;
  userManagement: {
    db: { user: UserManagementDB["user"]; role: UserManagementDB["role"] };
    queries: { listUsersByRole: UserManagementQueries["listUsersByRole"] };
  };
}

/* @__NO_SIDE_EFFECTS__ */
export const defineModule = <
  const PF extends Record<string, TailorAnyDBField> = EmptyFields,
  const PSF extends Record<string, TailorAnyDBField> = EmptyFields,
  const PSAF extends Record<string, TailorAnyDBField> = EmptyFields,
  const RF extends Record<string, TailorAnyDBField> = EmptyFields,
  const SF extends Record<string, TailorAnyDBField> = EmptyFields,
  const SAF extends Record<string, TailorAnyDBField> = EmptyFields,
  const DF extends Record<string, TailorAnyDBField> = EmptyFields,
>(
  params: DefineModuleParams<PF, PSF, PSAF, RF, SF, SAF, DF>,
) => {
  const approvalPolicy = createApprovalPolicyType(params.approvalPolicy ?? {});
  const approvalPolicyStep = createApprovalPolicyStepType(params.approvalPolicyStep ?? {});
  const approvalPolicyStepAssignee = createApprovalPolicyStepAssigneeType({
    ...params.approvalPolicyStepAssignee,
    userType: params.userManagement.db.user,
    roleType: params.userManagement.db.role,
  });
  const approvalRequest = createApprovalRequestType({
    ...params.approvalRequest,
    userType: params.userManagement.db.user,
  });
  const approvalStep = createApprovalStepType(params.approvalStep ?? {});
  const approvalStepAssignee = createApprovalStepAssigneeType({
    ...params.approvalStepAssignee,
    userType: params.userManagement.db.user,
    roleType: params.userManagement.db.role,
  });
  const approvalDecision = createApprovalDecisionType({
    ...params.approvalDecision,
    userType: params.userManagement.db.user,
  });

  const deps = { listUsersByRole: params.userManagement.queries.listUsersByRole };

  return {
    db: {
      approvalPolicy,
      approvalPolicyStep,
      approvalPolicyStepAssignee,
      approvalRequest,
      approvalStep,
      approvalStepAssignee,
      approvalDecision,
    },
    commands: {
      createApprovalPolicy: createApprovalPolicy(),
      updateApprovalPolicy: updateApprovalPolicy(),
      activateApprovalPolicy: activateApprovalPolicy(),
      deactivateApprovalPolicy: deactivateApprovalPolicy(),
      createApprovalRequest: createApprovalRequest(deps),
      withdrawApprovalRequest: withdrawApprovalRequest(),
      cancelApprovalRequest: cancelApprovalRequest(),
      approveApprovalStep: approveApprovalStep(deps),
      rejectApprovalStep: rejectApprovalStep(),
      delegateApprovalStep: delegateApprovalStep(),
    },
    queries: {
      listApprovalPolicies,
      getActiveApprovalRequest,
      listApprovalRequestsByTarget,
      listApprovalRequestsForApprover,
      getApprovalDecisionHistory,
    },
  };
};
