<template>
  <div :id="namespace + JSON.stringify(data.path)" class="routeBlock">
    <p class="badges">
      <a
        v-if="data?.heat"
        :href="`follow://discover?route=${encodeURIComponent(`/${namespace}${data.path}`)}`"
        target="_blank"
      >
        <Badge type="info">🔥 {{ data?.heat }}</Badge>
      </a>
      <Badge v-if="!test" type="warning">🟡 {{ t('badge.missingTest') }}</Badge>
      <Badge v-if="test && !test?.code" type="tip">🟢 {{ t('badge.passedTest') }}</Badge>
      <a v-if="data.features?.antiCrawler" :href="`${localePath}/guide/faqs`" target="_blank">
        <Badge type="danger">🚨 {{ t('badge.antiCrawling') }}</Badge>
      </a>
      <Badge v-if="data.features?.supportBT" type="tip">🔄 {{ t('badge.supportBT') }}</Badge>
      <Badge v-if="data.features?.supportPodcast" type="tip">🎙️ {{ t('badge.supportPodcast') }}</Badge>
      <Badge v-if="data.features?.supportScihub" type="tip">🧪 {{ t('badge.supportSciHub') }}</Badge>
      <Badge v-if="data.features?.requirePuppeteer" type="warning">🎭 {{ t('badge.relyPuppeteer') }}</Badge>
      <a
        v-if="data.features?.requireConfig"
        :href="`${localePath}/deploy/config#route-specific-configurations`"
        target="_blank"
      >
        <Badge type="warning">⚙️ {{ t('badge.configRequired') }}</Badge>
      </a>
      <a v-if="data.radar" :href="`${localePath}/guide/#radar`" target="_blank">
        <Badge type="tip">🔍 {{ t('badge.supportRadar') }}</Badge>
      </a>
    </p>
    <p class="author" style="display: flex; align-items: center; gap: 8px; flex-wrap: wrap">
      👨‍💻 {{ t('route.author') }}
      <a
        v-for="(uid, index) in data.maintainers"
        :key="index"
        :href="`https://github.com/${uid}`"
        target="_blank"
        style="display: inline-flex; align-items: center; margin-right: 6px"
      >
        <img
          :src="`https://avatars.githubusercontent.com/${uid}`"
          style="width: 20px; height: 20px; border-radius: 50%; margin-right: 4px"
        />
        {{ uid }}{{ ' ' }}
      </a>
    </p>
    <p v-if="demoUrl" class="example">
      <span>💡 {{ t('route.example') }}</span>
      <a :href="demoUrl" target="_blank">
        {{ demoUrl.replace(/^https:\/\//, '') }}
      </a>
      <CopyButton :text="demoUrl" />
      <button v-if="modified" class="copy reset" :title="t('route.reset')" @click="resetExample">
        <svg
          xmlns="http://www.w3.org/2000/svg"
          width="16"
          height="16"
          viewBox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          stroke-width="2"
          stroke-linecap="round"
          stroke-linejoin="round"
          class="lucide lucide-rotate-ccw"
        >
          <path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" />
          <path d="M3 3v5h5" />
        </svg>
      </button>
    </p>
    <div v-if="data.topFeeds?.length" class="top-feeds">
      <span>🔥 {{ t('route.topFeeds') }}</span>
      <ul>
        <li v-for="(item, index) in data.topFeeds" :key="index">
          <a :href="`https://app.follow.is/share/feeds/${item.id}`" target="_blank">
            {{ item.title }}
          </a>
        </li>
      </ul>
    </div>
    <p class="path" style="display: flex; align-items: center; gap: 8px">
      🛎️ {{ t('route.route') }}<code>/{{ namespace + data.path }}</code
      >{{ ' ' }}
      <CopyButton :text="`/${namespace}${data.path}`" />
      <a
        v-if="data.categories?.includes('popular')"
        :href="`follow://discover?route=${encodeURIComponent(`/${namespace}${data.path}`)}`"
        target="_blank"
        style="display: inline-flex; align-items: center"
      >
        <svg width="24" height="24" viewBox="0 0 145 145" fill="none" xmlns="http://www.w3.org/2000/svg">
          <mask id="mask0_54_296" maskUnits="userSpaceOnUse" x="0" y="0" width="145" height="145">
            <path
              fillRule="evenodd"
              clipRule="evenodd"
              d="M144.491 45.4541C144.491 43.75 144.492 42.0456 144.481 40.3413C144.473 38.9056 144.456 37.4702 144.417 36.0352C144.333 32.9075 144.148 29.753 143.592 26.6601C143.028 23.5227 142.107 20.6027 140.655 17.752C139.228 14.9501 137.364 12.3862 135.139 10.1633C132.915 7.94053 130.351 6.07747 127.548 4.65117C124.694 3.19908 121.771 2.27818 118.63 1.71424C115.537 1.15884 112.381 0.974699 109.254 0.890204C107.818 0.851354 106.382 0.834978 104.945 0.826093C103.24 0.81564 101.535 0.816511 99.8296 0.816511L80.0305 0.745605H65.2222L45.7734 0.816511C44.0649 0.816511 42.3564 0.81564 40.6479 0.826093C39.2085 0.834978 37.7698 0.851354 36.331 0.890204C33.196 0.974699 30.0335 1.15902 26.933 1.71511C23.7879 2.27887 20.8604 3.19943 18.0029 4.65047C15.194 6.07694 12.6239 7.94018 10.3953 10.1633C8.1671 12.386 6.29934 14.9494 4.86956 17.7508C3.41382 20.6028 2.49083 23.5246 1.92533 26.6638C1.36854 29.7554 1.18405 32.9089 1.09921 36.0352C1.06053 37.4704 1.04381 38.9057 1.03509 40.3413C1.02464 42.0458 0.937012 44.163 0.937012 45.8674L0.937534 65.0468L0.937012 80.0136L1.02551 99.6005C1.02551 101.307 1.02482 103.014 1.03509 104.72C1.04381 106.158 1.06053 107.595 1.09938 109.032C1.18405 112.164 1.36889 115.323 1.9262 118.42C2.49153 121.562 3.41434 124.486 4.86886 127.34C6.29882 130.146 8.16692 132.713 10.3953 134.939C12.6237 137.165 15.1932 139.031 18.0015 140.459C20.8607 141.913 23.7896 142.835 26.9366 143.4C30.0357 143.956 33.1972 144.141 36.331 144.225C37.7698 144.264 39.2087 144.281 40.648 144.289C42.3566 144.3 44.0649 144.299 45.7734 144.299L65.398 144.3H80.243L99.8296 144.299C101.535 144.299 103.24 144.3 104.945 144.289C106.382 144.281 107.818 144.264 109.254 144.225C112.383 144.141 115.539 143.956 118.634 143.399C121.773 142.835 124.694 141.913 127.547 140.46C130.35 139.031 132.915 137.166 135.139 134.939C137.363 132.714 139.227 130.147 140.654 127.341C142.107 124.486 143.028 121.56 143.593 118.416C144.148 115.321 144.333 112.163 144.417 109.032C144.456 107.595 144.473 106.158 144.481 104.72C144.492 103.014 144.491 101.307 144.491 99.6005C144.491 99.6005 144.49 80.3594 144.49 80.0136V65.0311C144.49 64.7757 144.491 45.4541 144.491 45.4541Z"
              fill="white"
            />
          </mask>
          <g mask="url(#mask0_54_296)">
            <rect x="0.414551" y="-6.74585" width="149.477" height="158.537" fill="#FF5C00" />
            <path
              d="M103.609 36.6948H53.5823C47.5327 36.6948 42.6284 41.5946 42.6284 47.6388C42.6284 53.683 47.5327 58.5828 53.5823 58.5828H103.609C109.659 58.5828 114.563 53.683 114.563 47.6388C114.563 41.5946 109.659 36.6948 103.609 36.6948Z"
              fill="white"
            />
            <path
              d="M76.9348 65.1489H43.5916C37.5419 65.1489 32.6377 70.0487 32.6377 76.0929C32.6377 82.1371 37.5419 87.0369 43.5916 87.0369H76.9348C82.9845 87.0369 87.8888 82.1371 87.8888 76.0929C87.8888 70.0487 82.9845 65.1489 76.9348 65.1489Z"
              fill="white"
            />
            <path
              d="M80.1608 104.571C80.1608 98.5272 75.2565 93.6274 69.2068 93.6274C63.1572 93.6274 58.2529 98.5272 58.2529 104.571C58.2529 110.616 63.1572 115.515 69.2068 115.515C75.2565 115.515 80.1608 110.616 80.1608 104.571Z"
              fill="white"
            />
          </g>
        </svg>
      </a>
    </p>

    <div v-if="paramMatch.length">
      <p>🔗 {{ t('route.parameters') }}</p>
      <ul>
        <li v-for="(item, index) in paramMatch" :key="index" class="params">
          <span style="display: flex; align-items: center; gap: 8px; flex-wrap: wrap">
            <code>{{ item.name }}</code>
            <Badge :type="necessityBadge[item.necessity]">{{ t(`param.${item.necessity}`) }}</Badge>
            <span v-if="item.default" :style="{ fontSize: '13px' }">
              <strong>{{ t('param.default') }}</strong> <code>{{ item.default }}</code>
            </span>
            <select
              v-if="item.options?.length"
              :style="{ fontSize: '13px' }"
              @change="updateExample(item.name, ($event.target as HTMLSelectElement).value)"
            >
              <option
                v-for="option in item.options"
                :key="option.value"
                :value="option.value"
                :selected="option.value === paramValues[item.name]"
              >
                {{ option.value }}: {{ option.label }}
              </option>
            </select>
          </span>
          <span :style="{ display: 'block', fontSize: '13px', lineHeight: 1.5 }" v-html="item.descriptionHtml" />
        </li>
      </ul>
    </div>
    <div v-if="data.features?.requireConfig">
      <p>⚙️ {{ t('route.deploymentConfigs') }}</p>
      <ul>
        <li v-for="(item, index) in data.features.requireConfig" :key="index" class="params">
          <code>{{ item.name }}</code
          >,{{ ' ' }}
          {{ item.optional ? t('config.optional') : t('config.required') }}
          {{ ' - ' }}
          <span v-html="renderMarkdown(item.description, true, t)" />
        </li>
      </ul>
    </div>
    <p class="path">
      🐙 {{ t('route.sourceCode') }}{{ ' ' }}
      <code>
        <a
          target="_blank"
          :href="`https://github.com/DIYgod/RSSHub/blob/master/lib/routes/${namespace}/${data.location}`"
          >/{{ namespace }}/{{ data.location }}</a
        >
      </code>
    </p>
    <!-- TODO: Render children if any -->
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';

import { renderMarkdown } from '../composables/markdown';
import { useLocale } from '../composables/useLocale';
import type { Route } from '../types';
import CopyButton from './CopyButton.vue';
import { parseJsonSchema } from './parse-json-schema';

const { t, localePath } = useLocale();

const props = defineProps<{
  namespace: string;
  data: Route & {
    heat?: number;
    topFeeds?: {
      id: string;
      url: string;
      title: string;
      description: string | null;
      siteUrl: string | null;
      image: string | null;
    }[];
    param?: any;
    query?: any;
    location?: string;
  };
  test?: {
    code: number;
    message?: string;
  };
}>();

const path = typeof props.data.path === 'string' ? props.data.path : props.data.path[0];
const param = parseJsonSchema(props.data.param);

const example = props.data.example ?? '';
const initialSegments = example.split('/');
const exampleSegments = [...initialSegments];

// Map each path parameter to its segment index in the example URL
const paramIndex: Record<string, number> = {};
`/${props.namespace}${path}`.split('/').forEach((segment, i) => {
  const name = segment.match(/^:(\w+)/)?.[1];
  if (name) {
    paramIndex[name] = i;
  }
});

// Pre-select each dropdown to the value already used in the example
const initialParamValues = () =>
  Object.fromEntries(Object.entries(paramIndex).map(([name, i]) => [name, initialSegments[i]]));
const paramValues = ref<Record<string, string>>(initialParamValues());

const initialDemoUrl = example ? 'https://rsshub.app' + example : null;
const demoUrl = ref(initialDemoUrl);
const modified = ref(false);

const updateExample = (name: string, value: string) => {
  const i = paramIndex[name];
  if (i === undefined || i > exampleSegments.length) {
    return;
  }
  exampleSegments[i] = value;
  paramValues.value[name] = value;
  demoUrl.value = 'https://rsshub.app' + exampleSegments.join('/');
  modified.value = true;
};

const resetExample = () => {
  exampleSegments.splice(0, exampleSegments.length, ...initialSegments);
  paramValues.value = initialParamValues();
  demoUrl.value = initialDemoUrl;
  modified.value = false;
};
//   `:name`        -> required
//   `:name?`       -> optional     (zero or one)
//   `:name{.+}`    -> one or more  (the `.+` regex matches across `/`, i.e. multiple segments)
//   `:name{.+}?`   -> zero or more
const paramMatch = [...path.matchAll(/:(?<name>\w+)(?:\{(?<regex>.+?)\})?(?<optional>\?)?/g)].map(({ groups }) => {
  const name = groups!.name;
  let parameter = param?.[name] || props.data.parameters?.[name];
  if (typeof parameter === 'string') {
    parameter = {
      description: parameter,
    };
  }
  const optional = groups!.optional === '?';
  const multiSegment = groups!.regex === '.+';
  const necessity = multiSegment ? (optional ? 'zeroOrMore' : 'oneOrMore') : optional ? 'optional' : 'required';
  const description = parameter?.description;
  const block = !!description && (description.includes('|') || description.includes(':::'));
  return {
    name,
    necessity,
    ...parameter,
    // Pre-render once so re-renders (i.e., on dropdown change) don't re-parse the markdown
    descriptionHtml: renderMarkdown(description || 'N/A', !block, t),
  };
});

const necessityBadge: Record<string, 'info' | 'tip' | 'warning' | 'danger'> = {
  required: 'warning',
  optional: 'tip',
  oneOrMore: 'info',
  zeroOrMore: 'info',
};
</script>
