import { __ } from '@wordpress/i18n';
import { useState, useEffect, useMemo, useRef } from '@wordpress/element';
import { useSelect } from '@wordpress/data';
import apiFetch from '@wordpress/api-fetch';
import { fetchAcfForPost, fetchAcfForTerm } from '../../../components/utils/acf-helpers';

// ─── DOM / text helpers ───────────────────────────────────────────────────────

const toPlain = (html = '') => {
  const tmp = document.createElement('div');
  tmp.innerHTML = html;
  return tmp.textContent || tmp.innerText || '';
};

const truncateWords = (str = '', words = 55) => {
  const parts = toPlain(str).trim().split(/\s+/);
  if (parts.length <= words) return parts.join(' ');
  return parts.slice(0, words).join(' ') + '…';
};

const formatDateSafe = (dateStr, dateFormat) => {
  try {
    const d = new Date(dateStr);
    if (!dateFormat) return d.toLocaleDateString();
    const pad = (n) => String(n).padStart(2, '0');
    const monthNames = [
      __('January','axcelersblocks'), __('February','axcelersblocks'), __('March','axcelersblocks'),
      __('April','axcelersblocks'),   __('May','axcelersblocks'),      __('June','axcelersblocks'),
      __('July','axcelersblocks'),    __('August','axcelersblocks'),   __('September','axcelersblocks'),
      __('October','axcelersblocks'), __('November','axcelersblocks'), __('December','axcelersblocks'),
    ];
    const Y = d.getFullYear(), m = d.getMonth() + 1, dnum = d.getDate(), F = monthNames[m - 1];
    const map = {
      'F j, Y': `${F} ${dnum}, ${Y}`,
      'Y-m-d':  `${Y}-${pad(m)}-${pad(dnum)}`,
      'm/d/Y':  `${pad(m)}/${pad(dnum)}/${Y}`,
      'd/m/Y':  `${pad(dnum)}/${pad(m)}/${Y}`,
    };
    return map[dateFormat] || d.toLocaleDateString();
  } catch { return ''; }
};

// ─── Hook ─────────────────────────────────────────────────────────────────────

/**
 * Manages all dynamic content fetching for the Bodycopy block.
 * Content may be plain text or HTML (excerpt, term description, ACF WYSIWYG).
 *
 * @param {object}   attributes    - Full block attributes.
 * @param {Function} setAttributes - Block setAttributes.
 * @returns {{ dynamicContent: string, postLink: string, authorLink: string, termLink: string, dynamicToken: string, isLoading: boolean }}
 */
export function useDynamicContent(attributes, setAttributes) {
  const {
    dynamicTag, selectedTag = 'post_excerpt',
    sourceEntity = 'post', sourceType = 'current',
    postId, postType, taxonomy = 'category', termId,
    dateFormat = '', excerptLength = 55, metaKey = '',
    termSeparator = ', ', acfField = '', acfScope = 'entity',
    required = true, fallbackText = '',
  } = attributes;

  const [dynamicContent, setDynamicContent] = useState('');
  const [isLoading,       setIsLoading]      = useState(false);
  const [postLink,        setPostLink]       = useState('#');
  const [authorLink,      setAuthorLink]     = useState('#');
  const [termLink,        setTermLink]       = useState('#');

  const { currentPostId, currentPostType } = useSelect((select) => {
    const { getCurrentPostId, getCurrentPostType } = select('core/editor');
    return { currentPostId: getCurrentPostId(), currentPostType: getCurrentPostType() };
  }, []);

  const [currentPostRestBase, setCurrentPostRestBase] = useState(currentPostType);
  const [taxRestBaseMap,      setTaxRestBaseMap]      = useState({});

  // Map current post type to its REST base
  useEffect(() => {
    if (!currentPostType) return;
    apiFetch({ path: '/wp/v2/types' })
      .then((types) => setCurrentPostRestBase(types[currentPostType]?.rest_base || currentPostType))
      .catch(() => setCurrentPostRestBase(currentPostType));
  }, [currentPostType]);

  // Fetch taxonomy → REST base map
  useEffect(() => {
    if (sourceEntity !== 'term' && selectedTag !== 'term_list') return;
    apiFetch({ path: '/wp/v2/taxonomies' })
      .then((taxData) => {
        const map = {};
        Object.values(taxData).forEach((t) => { if (t?.slug && t?.rest_base) map[t.slug] = t.rest_base; });
        setTaxRestBaseMap(map);
      })
      .catch(() => {});
  }, [sourceEntity, selectedTag]);

  // Keep postId / postType attributes in sync with the editor's current post
  useEffect(() => {
    if (sourceEntity !== 'post') return;
    if (sourceType === 'current' && currentPostId && (postId !== String(currentPostId) || postType !== currentPostType)) {
      setAttributes({ postId: String(currentPostId), postType: currentPostType });
    } else if (sourceType === 'specific' && postId === String(currentPostId || '')) {
      setAttributes({ postId: '' });
    }
  }, [sourceEntity, sourceType, currentPostId, currentPostType, postId, postType, setAttributes]);

  // ─── Helpers ─────────────────────────────────────────────────────────────

  const emptyOrFallback = (val) => {
    if (val || val === 0) return String(val);
    return required ? (fallbackText || '—') : '';
  };

  const buildPostEndpoint = () => {
    if (sourceType === 'current' && currentPostId) return `/wp/v2/${currentPostRestBase}/${currentPostId}`;
    if (sourceType === 'specific' && postId && postType) return `/wp/v2/${postType}/${postId}`;
    return null;
  };

  const buildTermEndpoint = () => {
    const restBase = taxRestBaseMap[taxonomy];
    if (!restBase || !termId) return null;
    return `/wp/v2/${restBase}/${termId}`;
  };

  // ─── Dynamic token (editor label) ────────────────────────────────────────

  const dynamicToken = useMemo(() => {
    if (dynamicTag) return dynamicTag;
    switch (selectedTag) {
      case 'post_excerpt':     return '{post_excerpt}';
      case 'post_date':        return '{post_date}';
      case 'post_author':      return '{post_author}';
      case 'comments_count':   return '{comments_count}';
      case 'comments_url':     return '{comments_url}';
      case 'post_title':       return '{post_title}';
      case 'post_permalink':   return '{post_permalink}';
      case 'post_meta':        return `{post_meta:${metaKey || 'meta_key'}}`;
      case 'term_list':        return `{term_list:${taxonomy || 'taxonomy'}}`;
      case 'term_name':        return '{term_name}';
      case 'term_description': return '{term_description}';
      case 'term_meta':        return `{term_meta:${metaKey || 'meta_key'}}`;
      case 'acf_field':        return `{acf_field:${acfField || 'field'}}`;
      default:                 return '{dynamic}';
    }
  }, [dynamicTag, selectedTag, metaKey, acfField, taxonomy]);

  // ─── Resolve from a post entity ───────────────────────────────────────────

  const resolveFromPost = async () => {
    const endpoint = buildPostEndpoint();
    if (!endpoint) { setDynamicContent(dynamicTag); setPostLink('#'); setAuthorLink('#'); return; }

    setIsLoading(true);
    try {
      const restBaseForTax = taxRestBaseMap[taxonomy] || taxonomy;
      const baseFields = ['id','title','link','author','excerpt','content','date','date_gmt','meta'];
      const fields = selectedTag === 'term_list'
        ? baseFields.concat(['categories','tags', restBaseForTax])
        : baseFields;

      const post = await apiFetch({ path: `${endpoint}?_fields=${fields.join(',')}` });
      setPostLink(post?.link || '#');

      switch (selectedTag) {
        case 'post_title':
          setDynamicContent(emptyOrFallback(post?.title?.rendered || ''));
          break;

        case 'post_excerpt': {
          const raw = post?.excerpt?.rendered || '';
          const fallback = post?.content?.rendered || '';
          setDynamicContent(raw ? raw : `<p>${truncateWords(fallback, excerptLength || 55)}</p>`);
          break;
        }

        case 'post_permalink':
          setDynamicContent(emptyOrFallback(post?.link || ''));
          break;

        case 'post_date': {
          const dateStr = post?.date || post?.date_gmt;
          setDynamicContent(emptyOrFallback(dateStr ? formatDateSafe(dateStr, dateFormat) : ''));
          break;
        }

        case 'post_meta': {
          let value = post?.meta?.[metaKey];
          if (typeof value === 'undefined' && metaKey) {
            try { const m = await apiFetch({ path: `${endpoint}?_fields=meta` }); value = m?.meta?.[metaKey]; } catch {}
          }
          const out = Array.isArray(value) ? value.join(', ') : (typeof value === 'object' ? JSON.stringify(value) : value);
          setDynamicContent(emptyOrFallback(out ?? ''));
          break;
        }

        case 'comments_count': {
          try {
            const res = await apiFetch({ path: `/wp/v2/comments?post=${post?.id || postId}&per_page=1`, parse: false });
            setDynamicContent(emptyOrFallback(res?.headers?.get?.('X-WP-Total') || '0'));
          } catch { setDynamicContent(emptyOrFallback('0')); }
          break;
        }

        case 'comments_url':
          setDynamicContent(emptyOrFallback((post?.link || '#') + '#comments'));
          break;

        case 'term_list': {
          const restBase = restBaseForTax;
          const ids = post?.[restBase] || post?.[taxonomy] || [];
          if (!ids?.length) { setDynamicContent(emptyOrFallback('')); break; }
          try {
            const terms = await apiFetch({ path: `/wp/v2/${restBase}?include=${ids.join(',')}&per_page=${ids.length}&_fields=id,name,link` });
            setDynamicContent(emptyOrFallback((terms || []).map((t) => t?.name).filter(Boolean).join(termSeparator || ', ')));
          } catch { setDynamicContent(emptyOrFallback('')); }
          break;
        }

        case 'post_author': {
          if (!post?.author) { setAuthorLink('#'); setDynamicContent(emptyOrFallback('')); break; }
          try {
            const author = await apiFetch({ path: `/wp/v2/users/${post.author}?_fields=name,link` });
            setAuthorLink(author?.link || '#');
            setDynamicContent(emptyOrFallback(author?.name || ''));
          } catch { setAuthorLink('#'); setDynamicContent(emptyOrFallback('')); }
          break;
        }

        case 'acf_field': {
          if (!acfField) { setDynamicContent(emptyOrFallback('')); break; }
          if (acfScope === 'options') {
            try {
              const opts = await apiFetch({ path: '/acf/v3/options/options' });
              let val = opts?.acf ? opts.acf[acfField] : undefined;
              if (typeof val === 'string' && /<[^>]+>/.test(val)) { setDynamicContent(val); }
              else { if (typeof val === 'object') val = JSON.stringify(val); setDynamicContent(emptyOrFallback(val ?? '')); }
            } catch { setDynamicContent(emptyOrFallback('')); }
          } else {
            try {
              const id      = (sourceType === 'specific' && postId) ? postId : currentPostId;
              const restBase = (sourceType === 'specific' && postType) ? postType : currentPostRestBase;
              let val = await fetchAcfForPost({ restBase, id, field: acfField });
              if (typeof val === 'string' && /<[^>]+>/.test(val)) { setDynamicContent(val); }
              else { if (typeof val === 'object') val = JSON.stringify(val); setDynamicContent(emptyOrFallback(val ?? '')); }
            } catch { setDynamicContent(emptyOrFallback('')); }
          }
          break;
        }

        default:
          setDynamicContent(emptyOrFallback(''));
      }
    } catch {
      setDynamicContent(required ? __('Error fetching post', 'axcelersblocks') : '');
      setPostLink('#'); setAuthorLink('#');
    } finally {
      setIsLoading(false);
    }
  };

  // ─── Resolve from a term entity ───────────────────────────────────────────

  const resolveFromTerm = async () => {
    const endpoint = buildTermEndpoint();
    if (!endpoint) { setDynamicContent(dynamicTag || ''); setTermLink('#'); return; }

    setIsLoading(true);
    try {
      const term = await apiFetch({ path: `${endpoint}?_fields=id,name,description,link,meta` });
      setTermLink(term?.link || '#');

      switch (selectedTag) {
        case 'term_name':
          setDynamicContent(emptyOrFallback(term?.name || ''));
          break;

        case 'term_description':
          setDynamicContent(term?.description || '');
          break;

        case 'term_meta': {
          const value = term?.meta?.[metaKey];
          const out = Array.isArray(value) ? value.join(', ') : (typeof value === 'object' ? JSON.stringify(value) : value);
          setDynamicContent(emptyOrFallback(out ?? ''));
          break;
        }

        case 'acf_field': {
          if (!acfField) { setDynamicContent(emptyOrFallback('')); break; }
          if (acfScope === 'options') {
            try {
              const opts = await apiFetch({ path: '/acf/v3/options/options' });
              let val = opts?.acf ? opts.acf[acfField] : undefined;
              if (typeof val === 'string' && /<[^>]+>/.test(val)) { setDynamicContent(val); }
              else { if (typeof val === 'object') val = JSON.stringify(val); setDynamicContent(emptyOrFallback(val ?? '')); }
            } catch { setDynamicContent(emptyOrFallback('')); }
          } else {
            try {
              const restBase = taxRestBaseMap[taxonomy] || taxonomy;
              let val = await fetchAcfForTerm({ taxonomy, restBase, id: termId, field: acfField });
              if (typeof val === 'string' && /<[^>]+>/.test(val)) { setDynamicContent(val); }
              else { if (typeof val === 'object') val = JSON.stringify(val); setDynamicContent(emptyOrFallback(val ?? '')); }
            } catch { setDynamicContent(emptyOrFallback('')); }
          }
          break;
        }

        default:
          setDynamicContent(emptyOrFallback(''));
      }
    } catch {
      setDynamicContent(required ? __('Error fetching term', 'axcelersblocks') : '');
      setTermLink('#');
    } finally {
      setIsLoading(false);
    }
  };

  // ─── Trigger resolution ───────────────────────────────────────────────────

  const resolveRef = useRef({ resolveFromPost, resolveFromTerm });
  resolveRef.current = { resolveFromPost, resolveFromTerm };

  useEffect(() => {
    if (!dynamicTag || !selectedTag) {
      setDynamicContent(''); setPostLink('#'); setAuthorLink('#'); setTermLink('#');
      return;
    }
    if (sourceEntity === 'term') {
      resolveRef.current.resolveFromTerm();
    } else {
      resolveRef.current.resolveFromPost();
    }
  }, [dynamicTag, selectedTag, sourceEntity, sourceType, postId, postType, currentPostId,
      currentPostRestBase, taxonomy, termId, taxRestBaseMap, dateFormat, excerptLength,
      metaKey, termSeparator, acfField, acfScope, required, fallbackText, dynamicToken]);

  return { dynamicContent, postLink, authorLink, termLink, dynamicToken, isLoading };
}
