import type { Meta, StoryObj } from '@storybook/vue3-vite';
import { defineComponent } from 'vue';
import './Catalog.scss';

type StoryModule = {
  default?: {
    title?: string;
    args?: Record<string, unknown>;
    parameters?: {
      docs?: {
        description?: {
          component?: string;
          story?: string;
        };
      };
    };
    render?: (...args: unknown[]) => unknown;
  };
  [key: string]: unknown;
};

const storyModules = import.meta.glob('../components/*/*.stories.ts', {
  eager: true,
}) as Record<string, StoryModule>;

const humanizeComponentName = (value: string) =>
  value
    .replace(/([a-z0-9])([A-Z])/g, '$1 $2')
    .replace(/[-_]+/g, ' ')
    .replace(/\b\w/g, (char) => char.toUpperCase())
    .trim();

const slugify = (value: string) =>
  value
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, '-')
    .replace(/^-+|-+$/g, '');

const getStoryHref = (title: string) => `/?path=/docs/${slugify(title)}--docs`;

const catalogStories = Object.entries(storyModules)
  .filter(([, module]) => Boolean(module.default?.title))
  .map(([filePath, module]) => {
    const meta = module.default ?? {};
    const storyName = Object.keys(module).find(
      (name) => name !== 'default' && name !== '__esModule',
    );
    const story = storyName ? (module[storyName] as StoryModule) : undefined;
    const render =
      typeof story?.render === 'function'
        ? story.render
        : typeof meta.render === 'function'
          ? meta.render
          : undefined;
    const args = {
      ...(meta.args ?? {}),
      ...(story?.args ?? {}),
    };
    const componentName =
      filePath.split('/components/')[1]?.split('/')[0] ??
      meta.title ??
      'Component';
    const rawTitle =
      (meta.title ?? componentName).split('/').pop() ?? componentName;

    return {
      filePath,
      title: humanizeComponentName(rawTitle),
      description:
        meta.parameters?.docs?.description?.component ??
        meta.parameters?.docs?.description?.story ??
        'Component documentation and examples.',
      storyHref: getStoryHref(meta.title ?? componentName),
      previewComponent:
        render && typeof render === 'function'
          ? defineComponent(render(args as never))
          : undefined,
    };
  })
  .sort((left, right) => left.title.localeCompare(right.title));

const meta: Meta = {
  title: 'Catalog',
  parameters: {
    controls: {
      disable: true,
    },
    docs: {
      controls: {
        disable: true,
      },
      description: {
        component: 'A live catalog of the library components.',
      },
      toc: false,
      canvas: { sourceState: 'none' },
    },
  },
};

export default meta;

type Story = StoryObj;

export const Default: Story = {
  render: () => ({
    setup() {
      return { catalogStories };
    },
    template: `
      <section
        class="catalog-grid"
      >
        <article
          v-for="entry in catalogStories"
          :key="entry.filePath"
          class="catalog-card"
        >
          <div
            class="catalog-preview"
          >
            <component :is="entry.previewComponent" v-if="entry.previewComponent" />
            <span v-else>{{ entry.title }}</span>
          </div>
          <h3
            class="catalog-title"
          >
            <a class="catalog-link" :href="entry.storyHref">{{ entry.title }}</a>
          </h3>
          <p
            class="catalog-description"
          >
            {{ entry.description }}
          </p>
        </article>
      </section>
    `,
  }),
  parameters: {
    docs: {
      canvas: {
        withToolbar: false,
      },
    },
  },
};
