/**
 * Minimal RichText implementation for rendering Bluesky post text.
 * Vendored from @atproto/api to avoid pulling in the full SDK (~150KB).
 *
 * Only implements segment iteration for read-only rendering.
 * Does not include text manipulation or facet detection.
 */

import type * as facet from "@/lib/lexicons/app/bsky/richtext/facet";

export type Facet = facet.Main;
export type FacetLink = facet.Link;
export type FacetMention = facet.Mention;
export type FacetTag = facet.Tag;

type Feature = Facet["features"][number];

const encoder = new TextEncoder();
const decoder = new TextDecoder();

class UnicodeString {
  utf16: string;
  utf8: Uint8Array;

  constructor(utf16: string) {
    this.utf16 = utf16;
    this.utf8 = encoder.encode(utf16);
  }

  get length() {
    return this.utf8.byteLength;
  }

  slice(start?: number, end?: number): string {
    return decoder.decode(this.utf8.slice(start, end));
  }
}

function isLink(f: Feature): f is FacetLink & { $type: "app.bsky.richtext.facet#link" } {
  return f.$type === "app.bsky.richtext.facet#link";
}

function isMention(f: Feature): f is FacetMention & { $type: "app.bsky.richtext.facet#mention" } {
  return f.$type === "app.bsky.richtext.facet#mention";
}

function isTag(f: Feature): f is FacetTag & { $type: "app.bsky.richtext.facet#tag" } {
  return f.$type === "app.bsky.richtext.facet#tag";
}

export class RichTextSegment {
  constructor(
    public text: string,
    public facet?: Facet,
  ) {}

  get link(): FacetLink | undefined {
    const found = this.facet?.features.find(isLink);
    return found ? { uri: found.uri } : undefined;
  }

  get mention(): FacetMention | undefined {
    const found = this.facet?.features.find(isMention);
    return found ? { did: found.did } : undefined;
  }

  get tag(): FacetTag | undefined {
    const found = this.facet?.features.find(isTag);
    return found ? { tag: found.tag } : undefined;
  }
}

export interface RichTextProps {
  text: string;
  facets?: Facet[];
}

export class RichText {
  private unicodeText: UnicodeString;
  private facets?: Facet[];

  constructor(props: RichTextProps) {
    this.unicodeText = new UnicodeString(props.text);
    if (props.facets?.length) {
      this.facets = props.facets
        .filter((f) => f.index.byteStart <= f.index.byteEnd)
        .sort((a, b) => a.index.byteStart - b.index.byteStart);
    }
  }

  *segments(): Generator<RichTextSegment, void, void> {
    const facets = this.facets || [];
    if (!facets.length) {
      yield new RichTextSegment(this.unicodeText.utf16);
      return;
    }

    let textCursor = 0;
    let facetCursor = 0;

    do {
      const currFacet = facets[facetCursor];
      if (textCursor < currFacet.index.byteStart) {
        yield new RichTextSegment(this.unicodeText.slice(textCursor, currFacet.index.byteStart));
      } else if (textCursor > currFacet.index.byteStart) {
        facetCursor++;
        continue;
      }
      if (currFacet.index.byteStart < currFacet.index.byteEnd) {
        const subtext = this.unicodeText.slice(currFacet.index.byteStart, currFacet.index.byteEnd);
        if (!subtext.trim()) {
          yield new RichTextSegment(subtext);
        } else {
          yield new RichTextSegment(subtext, currFacet);
        }
      }
      textCursor = currFacet.index.byteEnd;
      facetCursor++;
    } while (facetCursor < facets.length);

    if (textCursor < this.unicodeText.length) {
      yield new RichTextSegment(this.unicodeText.slice(textCursor, this.unicodeText.length));
    }
  }
}
