import type { VbenFormSchema } from '#/adapter/form';
import type { WordpressBlogApi } from '#/api/blog';

export type BlogArticleEditorMode = 'html-rich' | 'html-source' | 'markdown';
export type BlogArticleContentFormat = 'html' | 'markdown';
export type BlogArticleFormValues = WordpressBlogApi.ArticleBody & {
  editorMode?: BlogArticleEditorMode;
};

export const BLOG_ARTICLE_FORM_CLASS = 'blog-article-form';
export const BLOG_ARTICLE_MODAL_CLASS = 'blog-article-modal';
export const BLOG_ARTICLE_MODAL_CONTENT_CLASS = 'blog-article-modal__content';
export const BLOG_ARTICLE_CONTENT_FIELD_CLASS = 'blog-article-form__content';
export const BLOG_ARTICLE_HTML_RICH_CLASS = 'blog-article-form__html-rich';
export const BLOG_ARTICLE_HTML_TEXTAREA_CLASS =
  'blog-article-form__html-source';
export const BLOG_ARTICLE_MARKDOWN_MIN_HEIGHT = 560;

const ARGON_BASE_CODEBLOCK_PATTERN = /\b(?:wp-block-code|hljs-codeblock)\b/;
const SOURCE_ONLY_HTML_PATTERN =
  /\b(?:hljs-ln|hljs-control|fancybox-wrapper|lazyload|collapse-block|wp-block-(?!code\b)[\w-]+)/;
const HTML_TAG_PATTERN = /<\/?[a-z][\s\S]*>/i;

/**
 * Builds the content field schema for Markdown, rich HTML, or raw WordPress HTML preservation.
 * @param mode Current editor mode; source mode uses a raw textarea to avoid runtime DOM rewrites.
 * @param markdownEditor Markdown editor component used for normal local article authoring.
 * @param richHtmlEditor Tiptap HTML editor component used for plain HTML authoring.
 * @returns Vben form schema for the article content field.
 */
export function createBlogArticleContentSchema(
  mode: BlogArticleEditorMode,
  markdownEditor: unknown,
  richHtmlEditor?: unknown,
): VbenFormSchema {
  const common = {
    fieldName: 'content',
    formItemClass: BLOG_ARTICLE_CONTENT_FIELD_CLASS,
    label: '内容',
  };

  if (mode === 'html-source') {
    return {
      ...common,
      component: 'Textarea',
      componentProps: {
        autoSize: { maxRows: 30, minRows: 18 },
        class: BLOG_ARTICLE_HTML_TEXTAREA_CLASS,
        placeholder: '保留 WordPress / Argon HTML 原文，保存时仅做安全清洗',
      },
      controlClass: 'w-full',
      wrapperClass: 'items-stretch',
    } as VbenFormSchema;
  }

  if (mode === 'html-rich') {
    return {
      ...common,
      component: richHtmlEditor as VbenFormSchema['component'],
      componentProps: {
        class: BLOG_ARTICLE_HTML_RICH_CLASS,
        minHeight: BLOG_ARTICLE_MARKDOWN_MIN_HEIGHT,
        placeholder: '请输入 HTML 富文本正文',
      },
      controlClass: 'w-full',
      wrapperClass: 'items-stretch',
    } as VbenFormSchema;
  }

  return {
    ...common,
    component: markdownEditor as VbenFormSchema['component'],
    componentProps: {
      minHeight: BLOG_ARTICLE_MARKDOWN_MIN_HEIGHT,
      placeholder: '请输入 Markdown 正文',
    },
    controlClass: 'w-full',
    wrapperClass: 'items-stretch',
  } as VbenFormSchema;
}

/**
 * Builds the editor mode selector schema and forwards mode changes to the article list page.
 * @param onChange Callback that receives the next editor mode selected in the form.
 * @returns Vben form schema for selecting the article editor mode.
 */
export function createBlogArticleEditorModeSchema(
  onChange?: (mode: BlogArticleEditorMode) => void,
): VbenFormSchema {
  return {
    component: 'RadioGroup',
    componentProps: {
      buttonStyle: 'solid',
      onChange: (event: { target?: { value?: BlogArticleEditorMode } }) => {
        const mode = event?.target?.value;
        if (mode) onChange?.(mode);
      },
      options: [
        { label: 'Markdown', value: 'markdown' },
        { label: '富文本 HTML', value: 'html-rich' },
        { label: '源码 HTML', value: 'html-source' },
      ],
      optionType: 'button',
    },
    fieldName: 'editorMode',
    label: '编辑模式',
  } as VbenFormSchema;
}

/**
 * Maps the UI editor mode back to the API's persisted content format contract.
 * @param mode Current editor mode from the article form.
 * @returns API content format saved with the article.
 */
export function getContentFormatForEditorMode(
  mode: BlogArticleEditorMode,
): BlogArticleContentFormat {
  return mode === 'markdown' ? 'markdown' : 'html';
}

/**
 * Chooses the editor mode for an existing article without forcing Markdown source or imported Argon HTML into the wrong editor.
 * @param article Article row returned by the local blog API.
 * @returns Markdown for source-backed articles, source HTML for strong runtime DOM, rich HTML for plain tags.
 */
export function getBlogArticleEditorMode(
  article?: Partial<WordpressBlogApi.Article>,
): BlogArticleEditorMode {
  const html = getRenderedValue(article?.contentHtml || article?.content);
  if (!html) return 'markdown';
  if (SOURCE_ONLY_HTML_PATTERN.test(html)) return 'html-source';
  if (hasMarkdownSource(article)) return 'markdown';
  if (ARGON_BASE_CODEBLOCK_PATTERN.test(html)) return 'html-source';
  return HTML_TAG_PATTERN.test(html) ? 'html-rich' : 'markdown';
}

/**
 * Chooses the persisted content format for an existing article.
 * @param article Article row returned by the local blog API.
 * @returns API content format derived from the detected editor mode.
 */
export function getBlogArticleContentFormat(
  article?: Partial<WordpressBlogApi.Article>,
): BlogArticleContentFormat {
  return getContentFormatForEditorMode(getBlogArticleEditorMode(article));
}

/**
 * Builds form defaults for creating a new article from current table filters.
 * @param searchValues Active table search filters used to prefill category and tag fields.
 * @param searchValues.categories Active category filters copied into the create form.
 * @param searchValues.tags Active tag filters copied into the create form.
 * @returns Article form defaults in Markdown mode.
 */
export function getBlogArticleCreateFormDefaults(
  searchValues: {
    categories?: string[];
    tags?: string[];
  } = {},
): BlogArticleFormValues {
  return {
    categories: [...(searchValues.categories || [])],
    content: '',
    contentFormat: 'markdown',
    editorMode: 'markdown',
    excerpt: '',
    slug: '',
    status: 'draft',
    sticky: false,
    tags: [...(searchValues.tags || [])],
    title: '',
  };
}

/**
 * Builds edit form values, preserving WordPress/Argon HTML when the article depends on runtime classes.
 * @param row Article row selected from the article table.
 * @returns Form values and content format for the edit modal.
 */
export function getBlogArticleEditFormValues(
  row: WordpressBlogApi.Article,
): BlogArticleFormValues {
  const editorMode = getBlogArticleEditorMode(row);
  const contentFormat = getContentFormatForEditorMode(editorMode);

  return {
    categories: row.categories || [],
    content:
      contentFormat === 'html'
        ? getRenderedValue(row.contentHtml || row.content)
        : getEditableMarkdown(row.content, row.contentMarkdown),
    contentFormat,
    editorMode,
    excerpt: getRenderedText(row.excerpt),
    id: row.id,
    slug: row.slug || '',
    status: row.status || 'draft',
    sticky: !!row.sticky,
    tags: row.tags || [],
    title: getRenderedText(row.title),
  };
}

/**
 * Builds the API payload while preserving the current content format selected for the modal.
 * @param values Current form values from Vben Form.
 * @param editingId Current article id, or undefined for create.
 * @param editorMode Current editor mode.
 * @returns Payload accepted by the blog article save/update API.
 */
export function buildBlogArticleSubmitPayload(
  values: BlogArticleFormValues,
  editingId: string | undefined,
  editorMode: BlogArticleEditorMode,
): WordpressBlogApi.ArticleBody {
  const { editorMode: _editorMode, ...payloadValues } = values;
  return {
    ...payloadValues,
    contentFormat: getContentFormatForEditorMode(editorMode),
    id: editingId,
    title: values.title?.trim() || '',
  };
}

/**
 * Converts WordPress rendered fields or strings into readable plain text.
 * @param value Rendered field or string value.
 * @returns HTML-free text.
 */
export function getRenderedText(
  value?: string | WordpressBlogApi.RenderedField,
) {
  return stripHtml(getRenderedValue(value));
}

/**
 * Reads a rendered field without stripping HTML.
 * @param value Rendered field or string value.
 * @returns Raw/rendered string.
 */
function getRenderedValue(value?: string | WordpressBlogApi.RenderedField) {
  if (!value) return '';
  if (typeof value === 'string') return value;
  return value.raw || value.rendered || '';
}

/**
 * Detects whether the article still owns an editable Markdown source snapshot.
 * @param article Article row returned by the local blog API.
 * @returns true when Admin should prefer Milkdown unless strong runtime-only HTML is present.
 */
function hasMarkdownSource(article?: Partial<WordpressBlogApi.Article>) {
  return !!article?.contentMarkdown?.trim();
}

/**
 * Chooses editable Markdown from an API rendered field and its explicit Markdown source.
 * @param value Rendered field or string value.
 * @param markdown Explicit Markdown source saved on local articles.
 * @returns Markdown text for the Milkdown editor.
 */
function getEditableMarkdown(
  value?: string | WordpressBlogApi.RenderedField,
  markdown?: string,
) {
  if (markdown) return markdown;
  return getRenderedValue(value);
}

/**
 * Strips simple HTML tags from Admin labels and excerpts.
 * @param value HTML or text value.
 * @returns Trimmed text.
 */
function stripHtml(value: string) {
  return value
    .replaceAll(/<[^>]+>/g, '')
    .replaceAll('&nbsp;', ' ')
    .trim();
}
