"use client";

import { Suspense, use, useCallback } from "react";
import { ErrorBoundary } from "react-error-boundary";
import { useEditMode } from "./EditModeContext";
import type { TrailStop } from "@/data/queries";
import { EmbedCacheContext, StopEmbed } from "./StopEmbed";
import { extractLink } from "./utils/linkExtraction";
import { loadEmbed } from "@/app/loadEmbed";
import { blueskyUrlToAtUri } from "./utils/bluesky";
import "./TrailStopCard.css";

function EmbedLoading({ onDelete }: { onDelete?: () => void }) {
  return (
    <div className="BlueskyPostEmbed-container">
      <div className="BlueskyPostEmbed loading">
        <div className="BlueskyPostEmbed-loading">loading...</div>
      </div>
      {onDelete && (
        <button onClick={onDelete} className="BlueskyPostEmbed-deleteButton" title="remove link">
          ×
        </button>
      )}
    </div>
  );
}

function EmbedError({ onDelete }: { onDelete?: () => void }) {
  return (
    <div className="BlueskyPostEmbed-container">
      <div className="BlueskyPostEmbed error">
        <div className="BlueskyPostEmbed-error">couldn't load embed</div>
      </div>
      {onDelete && (
        <button onClick={onDelete} className="BlueskyPostEmbed-deleteButton" title="remove link">
          ×
        </button>
      )}
    </div>
  );
}

type Props = {
  stop: TrailStop;
  stepNumber: number;
  totalStops: number;
  isCurrent?: boolean;
};

export function TrailStopCard({ stop, stepNumber, totalStops, isCurrent = false }: Props) {
  const editContext = useEditMode();
  const isEditing = !!editContext;
  const updateStop = editContext?.updateStop;
  const error = editContext?.inlineErrors[stop.tid];
  const [embedCache, setEmbedCache] = use(EmbedCacheContext);

  const textareaRef = useCallback((el: HTMLTextAreaElement | null) => {
    if (el) {
      el.style.height = "auto";
      el.style.height = el.scrollHeight + "px";
    }
  }, []);

  const handleTitleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    if (updateStop) updateStop(stop.tid, { title: e.target.value });
  };

  const handleContentChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
    if (updateStop) updateStop(stop.tid, { content: e.target.value });
  };

  const handlePaste = async (e: React.ClipboardEvent<HTMLTextAreaElement>) => {
    // If there's already a link, just paste normally
    if (stop.external) return;

    const pastedText = e.clipboardData.getData("text");
    const extractedLink = extractLink(pastedText);
    if (!extractedLink || !updateStop || !embedCache) return;

    let linkUrl = extractedLink.uri;

    // Normalize bluesky URLs to at:// URIs
    if (extractedLink.type === "app.bsky.feed.post" && linkUrl.startsWith("http")) {
      const atUri = blueskyUrlToAtUri(linkUrl);
      if (atUri) linkUrl = atUri;
    }

    // Prevent default paste for special embed types
    const embedDomains = [
      "youtube.com",
      "youtu.be",
      "spotify.com",
      "soundcloud.com",
      "music.apple.com",
      "vimeo.com",
      "twitch.tv",
      "giphy.com",
      "tenor.com",
    ];
    const isSpecialEmbed =
      extractedLink.type === "app.sidetrail.trail" ||
      extractedLink.type === "app.bsky.feed.post" ||
      (() => {
        try {
          const host = new URL(linkUrl).hostname.replace(/^www\./, "");
          return embedDomains.some((d) => host === d || host.endsWith("." + d));
        } catch {
          return false;
        }
      })();

    if (isSpecialEmbed) {
      e.preventDefault();
    }

    // Start loading embed and add to cache
    const embedPromise = loadEmbed(linkUrl);
    const newCache = new Map(embedCache);
    newCache.set(linkUrl, embedPromise);
    setEmbedCache(newCache);

    // Update stop with the external link
    updateStop(stop.tid, { external: { uri: linkUrl } });
  };

  const handleRemoveLink = () => {
    if (!updateStop) return;
    setEmbedCache(new Map());

    const extractedLink = extractLink(stop.content);
    if (extractedLink?.type === "http") {
      updateStop(stop.tid, {
        content: stop.content.replace(extractedLink.uri, "").trim(),
        external: undefined,
      });
    } else {
      updateStop(stop.tid, { external: undefined });
    }
  };

  const handleButtonTextChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    if (updateStop) updateStop(stop.tid, { buttonText: e.target.value });
  };

  return (
    <div className="TrailStopCard">
      {error && isEditing && <div className="TrailStopCard-error">{error}</div>}

      <div className="TrailStopCard-header">
        {isEditing ? (
          <input
            type="text"
            value={stop.title}
            onChange={handleTitleChange}
            className={`TrailStopCard-titleEdit ${error ? "TrailStopCard-titleEdit--error" : ""}`}
            placeholder="name this stop"
          />
        ) : (
          stop.title && (
            <h2 className="TrailStopCard-title">
              <span>{stop.title}</span>
            </h2>
          )
        )}
        <div className="TrailStopCard-counter">
          Stop {stepNumber} of {totalStops}
        </div>
      </div>

      <div className="TrailStopCard-content">
        {isEditing ? (
          <textarea
            ref={textareaRef}
            value={stop.content}
            onChange={handleContentChange}
            onPaste={handlePaste}
            className="TrailStopCard-contentEdit"
            placeholder="what happens here?"
            rows={2}
            onInput={(e) => {
              e.currentTarget.style.height = "auto";
              e.currentTarget.style.height = e.currentTarget.scrollHeight + "px";
            }}
          />
        ) : (
          stop.content && <p className="TrailStopCard-text">{stop.content}</p>
        )}

        {stop.external && (
          <div
            className="TrailStopCard-embed"
            style={isEditing ? { opacity: 0.9, marginTop: "0.5rem" } : undefined}
          >
            <ErrorBoundary
              fallbackRender={() => (
                <EmbedError onDelete={isEditing ? handleRemoveLink : undefined} />
              )}
            >
              <Suspense
                fallback={<EmbedLoading onDelete={isEditing ? handleRemoveLink : undefined} />}
              >
                <StopEmbed
                  external={stop.external}
                  onDelete={isEditing ? handleRemoveLink : undefined}
                />
              </Suspense>
            </ErrorBoundary>
          </div>
        )}
      </div>

      {/* Custom button text shown when editing current step */}
      {isEditing && isCurrent && (
        <div className="TrailStopCard-buttonPreview">
          <input
            type="text"
            value={stop.buttonText || ""}
            onChange={handleButtonTextChange}
            className="TrailStopCard-buttonTextInput"
            placeholder="done that"
          />
        </div>
      )}
    </div>
  );
}
