import { getHubSpotClient } from "./client";

export async function getDealBatch(hubspotDealId: string): Promise<string | null> {
  try {
    const client = getHubSpotClient();
    const deal = await client.crm.deals.basicApi.getById(hubspotDealId, ["batch"]);
    return (deal.properties["batch"] as string | null | undefined) ?? null;
  } catch (err) {
    console.error("[HubSpot] getDealBatch failed", { dealId: hubspotDealId, error: err });
    return null;
  }
}

export async function syncRemovalRequestToHubSpot(params: {
  hubspotDealId: string;
  type: "removal" | "re_addition";
  status: "pending" | "approved" | "declined";
  reason: string;
  requestedByEmail: string;
  reviewedByEmail?: string | null;
  batchValue?: string | null;
}): Promise<void> {
  try {
    const client = getHubSpotClient();

    let statusLabel: string;
    if (params.type === "removal") {
      statusLabel =
        params.status === "pending"
          ? "Removal Request In Progress"
          : params.status === "approved"
            ? "Removed From Project"
            : "";
    } else {
      statusLabel =
        params.status === "pending"
          ? "Re-addition Requested"
          : params.status === "approved"
            ? ""
            : "Removed From Project";
    }

    let log = `Requested by: ${params.requestedByEmail}\nReason: ${params.reason}`;
    if (params.reviewedByEmail) {
      if (params.type === "re_addition" && params.status === "approved") {
        log += `\nRe-added to project by: ${params.reviewedByEmail}`;
      } else {
        const action = params.status === "approved" ? "Approved" : "Declined";
        log += `\n${action} by: ${params.reviewedByEmail}`;
      }
    }

    const properties: Record<string, string> = {
      project_removal_status: statusLabel,
      project_removal_request_log: log,
    };

    // Set batch when approving removal; restore it when approving re-addition (if we have a value)
    if (params.type === "removal" && params.status === "approved") {
      properties["batch"] = "Removed from Program";
    } else if (params.type === "re_addition" && params.status === "approved" && params.batchValue != null) {
      properties["batch"] = params.batchValue;
    }

    await client.crm.deals.basicApi.update(params.hubspotDealId, { properties });
  } catch (err) {
    console.error("[HubSpot] syncRemovalRequestToHubSpot failed", {
      dealId: params.hubspotDealId,
      error: err,
    });
  }
}

type MeasureUploadProgress = {
  measureName: string;
  uploadedCount: number;
  requiredCount: number;
  isComplete: boolean;
};

export async function syncContractorDocUploadToHubSpot(params: {
  hubspotDealId: string;
  measureProgress?: MeasureUploadProgress[];
}): Promise<void> {
  let log: string;
  let uploadStatus: string;
  if (params.measureProgress && params.measureProgress.length > 0) {
    log = params.measureProgress
      .map((m) => {
        if (m.isComplete) return `${m.measureName}: Complete (${m.uploadedCount}/${m.requiredCount} docs)`;
        if (m.uploadedCount > 0) return `${m.measureName}: In Progress (${m.uploadedCount}/${m.requiredCount} docs)`;
        return `${m.measureName}: Not Started (0/${m.requiredCount} docs)`;
      })
      .join(" | ");
    uploadStatus = params.measureProgress.every((m) => m.isComplete)
      ? "Upload Complete for All Measures"
      : "Upload in progress";
  } else {
    log = "Documents available - uploaded by contractor";
    uploadStatus = "Upload in progress";
  }

  const maxAttempts = 3;
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    try {
      const client = getHubSpotClient();
      await client.crm.deals.basicApi.update(params.hubspotDealId, {
        properties: {
          contractor_document_upload_log: log,
          contractor_document_upload_status: uploadStatus,
        },
      });
      return;
    } catch (err) {
      const isReset =
        err instanceof Error &&
        "code" in err &&
        (err as NodeJS.ErrnoException).code === "ECONNRESET";
      if (isReset && attempt < maxAttempts) {
        await new Promise((resolve) => setTimeout(resolve, 200 * attempt));
        continue;
      }
      console.error("[HubSpot] syncContractorDocUploadToHubSpot failed", {
        dealId: params.hubspotDealId,
        attempt,
        error: err,
      });
      return;
    }
  }
}

export async function syncMeasureApprovalsToHubSpot(params: {
  hubspotDealId: string;
  approvedMeasures: Array<{ measureName: string; approvedByEmail: string }>;
  actedByEmail: string;
  actedAt: Date;
}): Promise<void> {
  const dateStr = params.actedAt.toLocaleString("en-GB", {
    day: "2-digit",
    month: "short",
    year: "numeric",
    hour: "2-digit",
    minute: "2-digit",
    timeZone: "UTC",
    timeZoneName: "short",
  });

  const log =
    params.approvedMeasures.length === 0
      ? `All measures unapproved by ${params.actedByEmail} on ${dateStr}`
      : [
          `Approved measures (updated by ${params.actedByEmail} on ${dateStr}):`,
          ...params.approvedMeasures.map((m) => `- ${m.measureName} (approved by ${m.approvedByEmail})`),
        ].join("\r\n");

  const maxAttempts = 3;
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    try {
      const client = getHubSpotClient();
      await client.crm.deals.basicApi.update(params.hubspotDealId, {
        properties: {
          client_measures_approval_log: log,
        },
      });
      return;
    } catch (err) {
      const isReset =
        err instanceof Error &&
        "code" in err &&
        (err as NodeJS.ErrnoException).code === "ECONNRESET";
      if (isReset && attempt < maxAttempts) {
        await new Promise((resolve) => setTimeout(resolve, 200 * attempt));
        continue;
      }
      console.error("[HubSpot] syncMeasureApprovalsToHubSpot failed", {
        dealId: params.hubspotDealId,
        attempt,
        error: err,
      });
      return;
    }
  }
}
