"use client";

/* eslint-disable @typescript-eslint/no-explicit-any */
import { PortableText, createDataAttribute, stegaClean } from "next-sanity";
import {
  getFileAsset,
  getImageAsset,
  getImageDimensions,
  SanityFileAsset,
} from "@sanity/asset-utils";
import type {
  BlockContent,
  Button as SanityButton,
  SanityImageAsset,
} from "@/sanity/sanity.types";
import { client } from "@/sanity/client";
import LinkButton from "./link-button";
import Image from "next/image";
import Link from "next/link";
import { DownloadIcon } from "lucide-react";
import { useDeconstructLink } from "@/lib/link-client";
import { dynamicHeight, generateImageUrl } from "@/lib/image-url";
import { Button } from "./ui/button";
import { sanityConnection } from "@repo/sanity-connection";

const { projectId, dataset } = client.config();

export function Callout(props: any) {
  if (!props) {
    return null;
  }
  return (
    <div className="bg-secondary-500 text-secondary-50 shadow-lg rounded-md p-6 border my-6 border-gray-200">
      <PortableText
        value={props.value.content}
        components={{
          block: {
            h1: ({ children }: any) => <h1>{children}</h1>,
            h2: ({ children }: any) => <h2>{children}</h2>,
            h3: ({ children }: any) => <h3>{children}</h3>,
            h4: ({ children }: any) => <h4>{children}</h4>,
            h5: ({ children }: any) => <h5>{children}</h5>,
            h6: ({ children }: any) => <h6>{children}</h6>,
          },
        }}
      />
    </div>
  );
}

export function PortableButton(value: { value: SanityButton }) {
  const linkData = useDeconstructLink(value.value.link);
  return (
    <div className="flex justify-left">
      <LinkButton
        className="px-5"
        text={value.value.text ?? ""}
        color={"default"}
        linkData={linkData}
      />
    </div>
  );
}

export function PortableImage({
  value,
  isInline,
}: {
  value: SanityImageAsset;
  isInline: boolean;
}) {
  const { width, height } = getImageDimensions(value);
  const imageAsset = getImageAsset(value, {
    projectId: sanityConnection.projectId ?? "",
    dataset: sanityConnection.dataset ?? "",
  });
  const attr = createDataAttribute({
    id: imageAsset._id,
    type: imageAsset._type,
    workspace: "production",
  });

  return (
    <Image
      data-sanity={attr("body")}
      src={generateImageUrl(value)}
      width={
        isInline ? (width >= 100 ? 100 : width) : width >= 1200 ? 1200 : width
      }
      height={dynamicHeight(height, width, isInline)}
      alt={value.altText || " "}
      loading="lazy"
      className="border rounded-md shadow-md"
      style={{
        display: isInline ? "inline-block" : "block",
        aspectRatio: width / height,
        maxHeight: "400px",
        maxWidth: "100%",
        width: "auto",
      }}
    />
  );
}

export function PortableFile({ value }: { value: SanityFileAsset }) {
  const fileAsset = getFileAsset(value, {
    projectId: projectId ?? "",
    dataset: dataset ?? "",
  });
  const attr = createDataAttribute({
    id: fileAsset._id,
    type: fileAsset._type,
    workspace: "production",
  });

  const filename: string =
    fileAsset?.originalFilename ||
    `${fileAsset.extension.charAt(0).toUpperCase() + fileAsset.extension?.slice(1)} herunterladen`;

  return (
    <div className="flex justify-left">
      <LinkButton
        linkData={{ href: fileAsset.url, target: "" }}
        data-sanity={attr("body")}
        target="_blank"
        rel="noopener noreferrer"
        download
        showIcon={false}
        extraIcon={DownloadIcon}
        text={
          filename.length > 20
            ? `${filename.slice(0, 10)}...${filename.slice(-10)}`
            : filename
        }
      />
    </div>
  );
}

function CustomLink(props: { children: React.ReactNode; value?: any }) {
  const { value, children } = props;

  let linkUrl = null;
  let target = "_self";

  if (value?.href) {
    const href = value.href;

    if (href.type === "external" && href.url) {
      linkUrl = href.url;
      target = href.blank ? "_blank" : "_self";
    } else if (href.type === "internal" || href._type === "reference") {
      const resolved = useDeconstructLink(href);
      if (resolved) {
        const ButtonComponent = Button as any;
        return (
          <ButtonComponent variant="link" className="p-0 h-auto font-normal" asChild>
            <Link href={resolved}>
              {children}
            </Link>
          </ButtonComponent>
        );
      }
    } else if (typeof href === "string") {
      linkUrl = href;
    }
  }

  if (linkUrl) {
    const ButtonComponent = Button as any;
    return (
      <ButtonComponent variant="link" className="p-0 h-auto font-normal" asChild>
        <Link
          href={linkUrl}
          target={target}
          rel={target === "_blank" ? "noopener noreferrer" : undefined}
        >
          {children}
        </Link>
      </ButtonComponent>
    );
  }

  return <>{children}</>;
}

const components = {
  types: {
    image: PortableImage,
    button: PortableButton,
    callout: Callout,
    file: PortableFile,
  },
  block: {
    h1: ({ children }: any) => <h1>{children}</h1>,
    h2: ({ children }: any) => <h2>{children}</h2>,
    h3: ({ children }: any) => <h3>{children}</h3>,
    h4: ({ children }: any) => <h4>{children}</h4>,
    h5: ({ children }: any) => <h5>{children}</h5>,
    h6: ({ children }: any) => <h6>{children}</h6>,
  },
  marks: {
    left: ({ children }: { children: React.ReactNode }) => (
      <span style={{ textAlign: "left", width: "100%", display: "block" }}>
        {children}
      </span>
    ),
    center: ({ children }: { children: React.ReactNode }) => (
      <span style={{ textAlign: "center", width: "100%", display: "block" }}>
        {children}
      </span>
    ),
    right: ({ children }: { children: React.ReactNode }) => (
      <span style={{ textAlign: "right", width: "100%", display: "block" }}>
        {children}
      </span>
    ),
    textColor: ({
      children,
      value = { value: "" },
    }: {
      children: React.ReactNode;
      value?: { value: string };
    }) => <span style={{ color: stegaClean(value.value) }}>{children}</span>,
    highlightColor: ({
      children,
      value = { value: "" },
    }: {
      children: React.ReactNode;
      value?: { value: string };
    }) => (
      <span style={{ background: stegaClean(value.value) }}>{children}</span>
    ),
    link: CustomLink,
  },
};

export default function SanityBlock({ body }: { body: BlockContent }) {
  if (!body) {
    return null;
  }
  return <PortableText value={body} components={components} />;
}
