import {
  Opportunity as CwOpportunity,
  OpportunityMember as CwOpportunityMember,
  SoOppStatus as CwSoOppStatus,
} from "../../generated/prisma/client";
import { OpportunityInterest } from "../../../api/generated/prisma/client";
import { Translation, skipRow } from "./types";
import { TranslationContext } from "./context";

type ApiOpportunityRecord = {
  id: number;
  name: string;
  notes?: string | null;
  oppNarrative?: string | null;
  typeId: number;
  stageCwId?: number | null;
  stageId?: number | null;
  statusId?: number | null;
  taxCodeId?: number | null;
  interest?: OpportunityInterest | null;
  probability: number;
  source?: string | null;
  primarySalesRepId?: string | null;
  secondarySalesRepId?: string | null;
  companyId?: number | null;
  contactId?: number | null;
  siteId?: number | null;
  customerPO?: string | null;
  expectedCloseDate?: Date | null;
  pipelineChangeDate?: Date | null;
  dateBecameLead?: Date | null;
  closedDate?: Date | null;
  closedFlag: boolean;
  locationId?: number | null;
  closedById?: string | null;
  updatedBy: string;
  eneteredBy: string;
  createdAt: Date;
  updatedAt: Date;
};

type CwOpportunityWithMembers = CwOpportunity & {
  members?: Pick<
    CwOpportunityMember,
    "memberRecId" | "primarySalesFlag" | "secondarySalesFlag"
  >[];
  soOppStatus?: Pick<CwSoOppStatus, "closedFlag"> | null;
};

const toInterest = (
  value: number | null
): OpportunityInterest | null => {
  if (value == null) return null;
  if (value <= 1) return OpportunityInterest.COLD;
  if (value === 2) return OpportunityInterest.WARM;
  return OpportunityInterest.HOT;
};

export const opportunityTranslation: Translation<
  CwOpportunityWithMembers,
  ApiOpportunityRecord,
  TranslationContext
> = {
  values: [
    { from: "opportunityRecId", to: "id" },
    { from: "opportunityName", to: "name" },
    { from: "notes", to: "notes" },
    {
      from: "opportunityRecId",
      to: "oppNarrative",
      process: (value, context) => {
        if (value == null) return null;
        return context.opportunityNarrativeByOpportunityId.get(value) ?? null;
      },
    },
    {
      from: "soTypeRecId",
      to: "typeId",
      process: (value, context) => {
        if (value != null) return value;
        if (context.defaultOpportunityTypeId != null)
          return context.defaultOpportunityTypeId;
        skipRow("Opportunity missing type and no default type available");
      },
    },
    { from: "soPipelineRecId", to: "stageId" },
    { from: "soOppStatusRecId", to: "statusId" },
    { from: "taxCodeRecId", to: "taxCodeId" },
    {
      from: "soInterestRecId",
      to: "interest",
      process: toInterest,
    },
    {
      from: "probabilityToClose",
      to: "probability",
      process: (value) => (value == null ? 0 : value),
    },
    { from: "source", to: "source" },
    {
      from: "opportunityRecId",
      to: "primarySalesRepId",
      process: (_value, context, row) => {
        const primary = row.members?.find((member) => member.primarySalesFlag);
        if (!primary) return null;
        return (
          context.userIdentifiersByMemberRecId.get(primary.memberRecId) ?? null
        );
      },
    },
    {
      from: "opportunityRecId",
      to: "secondarySalesRepId",
      process: (_value, context, row) => {
        const secondary = row.members?.find(
          (member) => member.secondarySalesFlag
        );
        if (!secondary) return null;
        return (
          context.userIdentifiersByMemberRecId.get(secondary.memberRecId) ??
          null
        );
      },
    },
    { from: "companyRecId", to: "companyId" },
    { from: "contactRecId", to: "contactId" },
    { from: "ownerLevelRecId", to: "locationId" },
    { from: "companyAddressRecId", to: "siteId" },
    { from: "poNumber", to: "customerPO" },
    { from: "dateCloseExpected", to: "expectedCloseDate" },
    { from: "datePipelineChange", to: "pipelineChangeDate" },
    { from: "dateBecameLead", to: "dateBecameLead" },
    { from: "dateClosed", to: "closedDate" },
    {
      from: "oldCloseFlag",
      to: "closedFlag",
      process: (_value, _context, row) =>
        row.soOppStatus?.closedFlag ?? row.oldCloseFlag ?? false,
    },
    { from: "closedBy", to: "closedById" },
    {
      from: "updatedBy",
      to: "updatedBy",
      process: (value) => (value ? value : "system"),
    },
    {
      from: "enteredBy",
      to: "eneteredBy",
      process: (value) => (value ? value : "system"),
    },
    { from: "dateBecameLeadUtc", to: "createdAt" },
    { from: "lastUpdatedUtc", to: "updatedAt" },
  ],
};
