"use client";

import { DownloadIcon } from "@/components/Tables/icons";
import { tendersService } from "@/lib/api/services/tenders-service";
import type { TTenderDocumentsResponse } from "@/lib/api/types/Tenders";
import {
  formatFileSize,
  saveBlobFromAxiosResponse,
  unixToDate,
} from "@/utils/shared";
import type { AxiosResponse } from "axios";
import { useCallback, useState } from "react";
import { toast } from "react-toastify";
import { HEADER_SCROLL_MARGIN, TENDER_SECTION_IDS } from "../constants";
import { SectionHeading } from "./section-heading";

type TenderDocumentsSectionProps = {
  tenderId: string;
  documents: TTenderDocumentsResponse[];
  isLoading: boolean;
};

const DOWNLOAD_STAGGER_MS = 400;

function headerContentType(response: AxiosResponse<Blob>) {
  const raw = response.headers["content-type"];
  return typeof raw === "string" ? raw : String(raw ?? "");
}

async function assertBlobNotJsonError(response: AxiosResponse<Blob>) {
  const ct = headerContentType(response).toLowerCase();
  if (!ct.includes("application/json")) return;
  const text = await response.data.text();
  let message = "Download failed";
  try {
    const body = JSON.parse(text) as { message?: string };
    if (body?.message) message = body.message;
  } catch {
    /* keep default */
  }
  throw new Error(message);
}

export function TenderDocumentsSection({
  tenderId,
  documents,
  isLoading,
}: TenderDocumentsSectionProps) {
  const [downloadingName, setDownloadingName] = useState<string | null>(null);
  const [isDownloadingAll, setIsDownloadingAll] = useState(false);

  const fetchDocument = useCallback(
    async (filename: string) => {
      const res = await tendersService.downloadTenderDocument(
        tenderId,
        filename,
      );
      await assertBlobNotJsonError(res);
      return res;
    },
    [tenderId],
  );

  const downloadOne = useCallback(
    async (filename: string) => {
      setDownloadingName(filename);
      try {
        const res = await fetchDocument(filename);
        saveBlobFromAxiosResponse(res, filename);
        toast.success(`Downloaded ${filename}`);
      } catch (e) {
        const message = e instanceof Error ? e.message : "Download failed";
        toast.error(message);
      } finally {
        setDownloadingName(null);
      }
    },
    [fetchDocument],
  );

  const downloadAllSequential = useCallback(async () => {
    let ok = 0;
    for (let i = 0; i < documents.length; i++) {
      const doc = documents[i];
      setDownloadingName(doc.filename);
      try {
        const res = await fetchDocument(doc.filename);
        saveBlobFromAxiosResponse(res, doc.filename);
        ok++;
      } catch (e) {
        const message = e instanceof Error ? e.message : "Download failed";
        toast.error(`${doc.filename}: ${message}`);
      } finally {
        setDownloadingName(null);
      }
      if (i < documents.length - 1) {
        await new Promise((r) => setTimeout(r, DOWNLOAD_STAGGER_MS));
      }
    }
    if (ok > 0) {
      toast.success(
        ok === documents.length
          ? `Downloaded all ${ok} files`
          : `Downloaded ${ok} of ${documents.length} files`,
      );
    }
  }, [documents, fetchDocument]);

  const handleDownloadAll = useCallback(async () => {
    if (documents.length === 0) return;
    setIsDownloadingAll(true);
    try {
      const res = await tendersService.downloadTenderDocumentsArchive(tenderId);
      const ct = headerContentType(res).toLowerCase();
      if (!ct.includes("application/json")) {
        saveBlobFromAxiosResponse(res, `tender-${tenderId}-documents.zip`);
        toast.success("Archive downloaded");
        return;
      }
      await res.data.text();
      await downloadAllSequential();
    } catch {
      await downloadAllSequential();
    } finally {
      setIsDownloadingAll(false);
    }
  }, [documents, downloadAllSequential, tenderId]);

  return (
    <div id={TENDER_SECTION_IDS.documents} className={HEADER_SCROLL_MARGIN}>
      <div className="mb-4 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
        <div className="min-w-0 flex-1">
          <SectionHeading>Documents</SectionHeading>
        </div>
        {documents.length > 0 && (
          <button
            type="button"
            disabled={isDownloadingAll || Boolean(downloadingName)}
            onClick={() => void handleDownloadAll()}
            className="inline-flex shrink-0 items-center justify-center gap-2 rounded-xl border border-primary/35 bg-primary/10 px-4 py-2.5 text-sm font-semibold text-primary transition hover:bg-primary/15 disabled:cursor-not-allowed disabled:opacity-50 dark:border-primary/45 dark:bg-primary/15 dark:text-white dark:hover:bg-primary/25"
          >
            <DownloadIcon className="h-4 w-4 shrink-0" />
            {isDownloadingAll ? "Downloading…" : "Download all"}
          </button>
        )}
      </div>

      <div className="rounded-2xl border border-stroke/60 bg-gray-2/40 shadow-inner dark:border-dark-3 dark:bg-dark-3/30">
        {isLoading && (
          <div className="space-y-3 p-6">
            <div className="h-4 w-2/3 animate-pulse rounded bg-stroke/80 dark:bg-dark-3" />
            <div className="h-4 w-1/2 animate-pulse rounded bg-stroke/80 dark:bg-dark-3" />
            <div className="h-4 w-3/4 animate-pulse rounded bg-stroke/80 dark:bg-dark-3" />
          </div>
        )}

        {!isLoading && documents.length === 0 && (
          <p className="p-6 text-sm text-dark-5 dark:text-dark-6">
            No documents are available for this tender.
          </p>
        )}

        {!isLoading && documents.length > 0 && (
          <ul className="divide-y divide-stroke/60 dark:divide-dark-3">
            {documents.map((doc) => {
              const busy =
                downloadingName === doc.filename ||
                (isDownloadingAll && downloadingName === doc.filename);
              return (
                <li
                  key={doc.filename}
                  className="flex flex-col gap-3 p-4 sm:flex-row sm:items-center sm:justify-between sm:gap-4"
                >
                  <div className="min-w-0 flex-1 space-y-1">
                    <p className="truncate text-sm font-medium text-dark dark:text-white">
                      {doc.filename}
                    </p>
                    <div className="flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-dark-5 dark:text-dark-6">
                      <span className="rounded-md bg-white/80 px-2 py-0.5 font-medium uppercase tracking-wide text-primary dark:bg-dark-2/80 dark:text-primary">
                        {doc.document_type}
                      </span>
                      <span>{formatFileSize(doc.size)}</span>
                      <span>
                        Updated{" "}
                        {unixToDate({
                          unix: doc.last_modified,
                          hasTime: true,
                        })}
                      </span>
                    </div>
                  </div>
                  <button
                    type="button"
                    disabled={
                      Boolean(downloadingName) || isDownloadingAll || busy
                    }
                    onClick={() => void downloadOne(doc.filename)}
                    className="inline-flex shrink-0 items-center justify-center gap-2 rounded-lg border border-stroke/70 bg-white px-3 py-2 text-sm font-medium text-dark shadow-sm transition hover:border-primary/40 hover:text-primary disabled:cursor-not-allowed disabled:opacity-50 dark:border-dark-3 dark:bg-dark-2 dark:text-gray-5 dark:hover:border-primary/40 dark:hover:text-white"
                    aria-label={`Download ${doc.filename}`}
                  >
                    <DownloadIcon className="h-4 w-4" />
                    {busy ? "…" : "Download"}
                  </button>
                </li>
              );
            })}
          </ul>
        )}
      </div>
    </div>
  );
}
