---
import { getCollection } from 'astro:content';
import ContentWidth from '@/components/frames/ContentWidth.astro';
import MarkdownCode from '@/components/typography/MarkdownCode.astro';
import Table from '@/components/typography/Table.astro';
import Tbody from '@/components/typography/Tbody.astro';
import Td from '@/components/typography/Td.astro';
import Th from '@/components/typography/Th.astro';
import Thead from '@/components/typography/Thead.astro';
import Tr from '@/components/typography/Tr.astro';
import { isValidFramework } from '@/types/docs';
import type { PresetReference as PresetReferenceType } from '@/types/preset-reference';
import DocsLink from '../DocsLink.astro';
import FrameworkCase from '../FrameworkCase.astro';
import InlineMarkdown from './InlineMarkdown.astro';

const entries = await getCollection('presetReference');
const PINNED_PRESETS = ['video', 'audio'];
const presets: PresetReferenceType[] = entries
  .map((e) => e.data)
  .sort((a, b) => {
    const aPin = PINNED_PRESETS.indexOf(a.name);
    const bPin = PINNED_PRESETS.indexOf(b.name);
    if (aPin !== -1 && bPin !== -1) return aPin - bPin;
    if (aPin !== -1) return -1;
    if (bPin !== -1) return 1;
    return a.name.localeCompare(b.name);
  });

const { framework } = Astro.params;
const pkg = framework && isValidFramework(framework) ? `@videojs/${framework}` : '@videojs/html';

/**
 * Native media elements used by presets that don't have a custom element.
 * The pipeline can't detect these since they're not classes with `static tagName`.
 */
const NATIVE_MEDIA_ELEMENTS: Record<string, string> = {
  video: 'video',
  audio: 'audio',
};

function htmlMediaElement(preset: PresetReferenceType): string | undefined {
  return preset.html.mediaElement ?? NATIVE_MEDIA_ELEMENTS[preset.name];
}

const listFormat = new Intl.ListFormat('en', { style: 'long', type: 'unit' });
---

<ContentWidth>
  <Table maxWidth={false} outerClass="my-6">
    <Thead>
      <Tr>
        <Th>Import</Th>
        <Th>Description</Th>
        <Th><span class="sr-only">Details</span></Th>
      </Tr>
    </Thead>
    <Tbody>
      {
        presets.map((preset) => {
          const id = `preset-${preset.name}`;
          const htmlMedia = htmlMediaElement(preset);
          return (
            <>
              <Tr
                id={id}
                data-preset-row
                class="group cursor-pointer data-expanded:border-transparent dark:data-expanded:border-transparent intent:bg-manila-75 dark:intent:bg-soot"
              >
                <Td class="align-top">
                  <MarkdownCode>{`${pkg}/${preset.name}`}</MarkdownCode>
                </Td>
                <Td class="align-top">
                  {preset.description && (
                    <InlineMarkdown content={preset.description} />
                  )}
                </Td>
                <Td class="align-top">
                  <button
                    aria-expanded="false"
                    aria-controls={`${id}-detail`}
                    aria-label={`Details for ${preset.name} preset`}
                    data-preset-toggle
                  >
                    <span
                      aria-hidden="true"
                      class="inline-block group-data-expanded:rotate-90"
                    >
                      ▸
                    </span>
                  </button>
                </Td>
              </Tr>
              <Tr id={`${id}-detail`} hidden>
                <Td colspan="3" class="p-0">
                  <div class="px-6 py-4">
                    <dl
                      class="grid grid-cols-(--grid-cols) gap-x-6 gap-y-3"
                      style="--grid-cols: auto 1fr"
                    >
                      <dt class="font-bold">Feature bundle</dt>
                      <dd>
                        <MarkdownCode>{preset.featureBundle}</MarkdownCode>
                      </dd>

                      <dt class="font-bold">Features</dt>
                      <dd>
                        {preset.features.length > 0
                          ? listFormat
                              .formatToParts(preset.features.map((f) => f.name))
                              .map((part) => {
                                if (part.type !== "element") {
                                  return <span>{part.value}</span>;
                                }
                                const feature = preset.features.find(
                                  (f) => f.name === part.value,
                                )!;
                                return feature.hasReference ? (
                                  <DocsLink
                                    class="inline-block whitespace-nowrap"
                                    slug={feature.slug}
                                  >
                                    {feature.name}
                                  </DocsLink>
                                ) : (
                                  <span class="inline-block whitespace-nowrap">
                                    {feature.name}
                                  </span>
                                );
                              })
                          : "–"}
                      </dd>

                      <dt class="font-bold">Skins</dt>
                      <dd>
                        <FrameworkCase frameworks={["react"]}>
                          {preset.react.skins.length > 0
                            ? preset.react.skins.map((skin) => (
                                <div class="mb-2 last:mb-0">
                                  <MarkdownCode class="inline-block whitespace-nowrap">{`<${skin.name}>`}</MarkdownCode>
                                  {skin.cssImport && (
                                    <div class="mt-0.5">
                                      <MarkdownCode class="inline-block text-code whitespace-nowrap">{`import '${skin.cssImport}';`}</MarkdownCode>
                                    </div>
                                  )}
                                </div>
                              ))
                            : "–"}
                        </FrameworkCase>
                        <FrameworkCase frameworks={["html"]}>
                          {preset.html.skins.length > 0
                            ? listFormat
                                .formatToParts(
                                  preset.html.skins.map(
                                    (s) => s.tagName ?? s.name,
                                  ),
                                )
                                .map((part) =>
                                  part.type === "element" ? (
                                    <MarkdownCode class="inline-block whitespace-nowrap">{`<${part.value}>`}</MarkdownCode>
                                  ) : (
                                    <span>{part.value}</span>
                                  ),
                                )
                            : "–"}
                        </FrameworkCase>
                      </dd>

                      <dt class="font-bold">Default media element</dt>
                      <dd>
                        <FrameworkCase frameworks={["react"]}>
                          <MarkdownCode>{`<${preset.react.mediaElement}>`}</MarkdownCode>
                        </FrameworkCase>
                        <FrameworkCase frameworks={["html"]}>
                          {htmlMedia ? (
                            <MarkdownCode>{`<${htmlMedia}>`}</MarkdownCode>
                          ) : (
                            "–"
                          )}
                        </FrameworkCase>
                      </dd>
                    </dl>
                  </div>
                </Td>
              </Tr>
            </>
          );
        })
      }
    </Tbody>
  </Table>
</ContentWidth>

<script>
  document
    .querySelectorAll<HTMLButtonElement>("[data-preset-toggle]")
    .forEach((button) => {
      button.addEventListener("click", () => {
        const expanded = button.getAttribute("aria-expanded") === "true";
        button.setAttribute("aria-expanded", String(!expanded));

        const row = button.closest<HTMLTableRowElement>("[data-preset-row]");
        if (row) row.toggleAttribute("data-expanded", !expanded);

        const detail = document.getElementById(
          button.getAttribute("aria-controls")!,
        );
        if (detail) detail.hidden = expanded;
      });
    });

  document
    .querySelectorAll<HTMLTableRowElement>("[data-preset-row]")
    .forEach((row) => {
      row.addEventListener("click", (e) => {
        if ((e.target as Element).closest("a, button")) return;
        row.querySelector<HTMLButtonElement>("[data-preset-toggle]")?.click();
      });
    });
</script>
