import { __ } from '@wordpress/i18n';
import { Modal, Button, SelectControl, TextControl, ToggleControl } from '@wordpress/components';
import { useEffect, useMemo, useReducer, useRef } from '@wordpress/element';
import apiFetch from '@wordpress/api-fetch';

// ===== Static config =====
const dynamicTagOptions = [
  { label: 'Post Title', value: 'post_title' },
  { label: 'Post Excerpt', value: 'post_excerpt' },
  { label: 'Post Permalink', value: 'post_permalink' },
  { label: 'Post Date', value: 'post_date' },
  { label: 'Post Meta', value: 'post_meta' },
  { label: 'Comments Count', value: 'comments_count' },
  { label: 'Comments URL', value: 'comments_url' },
  { label: 'Term List', value: 'term_list' },
  { label: 'Author', value: 'post_author' },
	{ label: 'Featured Image', value: 'featured_image' },
	{ label: 'Author Avatar', value: 'author_avatar' },
  // Term-specific tags
  { label: 'Term Name', value: 'term_name' },
  { label: 'Term Description', value: 'term_description' },
  { label: 'Term Meta', value: 'term_meta' },
  // ACF
  { label: 'ACF Field', value: 'acf_field' },
];

// ===== Simple in-memory caches (per editor session) =====
const postsCache = new Map();
let taxonomiesCache = null;
const termsCache = new Map();

// ===== Reducer =====
const initialState = {
  isLoading: false,
  postsGrouped: {},
  taxonomies: [],
  termsByTax: {},
  requiredLocal: true,
};

function reducer(state, action) {
  switch (action.type) {
    case 'SET_LOADING':
      return { ...state, isLoading: action.payload };
    case 'SET_POSTS_GROUPED':
      return { ...state, postsGrouped: action.payload };
    case 'SET_TAXONOMIES':
      return { ...state, taxonomies: action.payload };
    case 'SET_TERMS_FOR_TAX':
      return {
        ...state,
        termsByTax: { ...state.termsByTax, [action.taxonomy]: action.terms },
      };
    case 'SET_REQUIRED_LOCAL':
      return { ...state, requiredLocal: action.payload };
    default:
      return state;
  }
}

const DynamicContentModal = ({ isOpen, onClose, onInsert, attributes, setAttributes, allowedTags, isButtonBlock = false,
}) => {
  const { selectedTag, sourceType, sourceEntity, postId, postType, taxonomy, termId, linkOption, dateFormat, excerptLength, metaKey, termSeparator, acfField, acfScope, required, } = attributes;

  const [state, dispatch] = useReducer(reducer, {
    ...initialState,
    requiredLocal: required ?? true,
  });

  // prevent concurrent fetches
  const fetchingRef = useRef({ posts: false, tax: false, terms: new Set() });

  // Filter tags if needed
  const tagOptions = useMemo(() => {
    const base = allowedTags
      ? dynamicTagOptions.filter((o) => allowedTags.includes(o.value))
      : dynamicTagOptions;
    return [{ label: __('— Select —', 'axcelersblocks'), value: '' }, ...base];
  }, [allowedTags]);

  // Derived booleans
  const needsDateFormat = selectedTag === 'post_date';
  const needsExcerptLen = selectedTag === 'post_excerpt';
  const needsMetaKey = selectedTag === 'post_meta' || selectedTag === 'term_meta';
  const needsTermSeparator = selectedTag === 'term_list';
  const needsTaxonomy = sourceEntity === 'term' || selectedTag === 'term_list';
	const needsTermPick = sourceEntity === 'term' && ( ['term_name', 'term_description', 'term_meta'].includes(selectedTag) || (selectedTag === 'acf_field' && (acfScope || 'entity') === 'entity') );
  const needsACF = selectedTag === 'acf_field';

  // ===== Fetch: Posts (specific) with caching =====
  useEffect(() => {
    if (!isOpen || sourceEntity !== 'post' || sourceType !== 'specific') return;
    if (fetchingRef.current.posts) return;

    dispatch({ type: 'SET_LOADING', payload: true });

    // Always fetch types (cheap), then fetch posts per type only if not cached
    apiFetch({ path: '/wp/v2/types' })
      .then((typesData) => {
        const filteredTypes = Object.values(typesData).filter(
          (type) =>
            type.rest_base &&
            !type.slug.startsWith('wp_') &&
            !['attachment', 'nav_menu_item'].includes(type.slug)
        );

        const fetchPromises = filteredTypes.map((type) => {
          if (postsCache.has(type.rest_base)) return Promise.resolve();
          return apiFetch({
            path: `/wp/v2/${type.rest_base}?per_page=100&_fields=id,title,link`,
          })
            .then((res) => postsCache.set(type.rest_base, res || []))
            .catch(() => postsCache.set(type.rest_base, []));
        });

        return Promise.all(fetchPromises).then(() => filteredTypes);
      })
      .then((filteredTypes) => {
        const grouped = {};
        filteredTypes.forEach((type) => {
          grouped[type.slug] = {
            label: type.name,
            restBase: type.rest_base,
            posts: postsCache.get(type.rest_base) || [],
          };
        });
        dispatch({ type: 'SET_POSTS_GROUPED', payload: grouped });
      })
      .finally(() => dispatch({ type: 'SET_LOADING', payload: false }));
  }, [isOpen, sourceType, sourceEntity]);

  // ===== Fetch: Taxonomies (with caching) =====
  useEffect(() => {
    if (!isOpen || (sourceEntity !== 'term' && selectedTag !== 'term_list')) return;
    if (fetchingRef.current.tax) return;

    if (taxonomiesCache) {
      dispatch({ type: 'SET_TAXONOMIES', payload: taxonomiesCache });
      return;
    }

    dispatch({ type: 'SET_LOADING', payload: true });
    fetchingRef.current.tax = true;

    apiFetch({ path: '/wp/v2/taxonomies' })
      .then((taxData) => {
        const list = Object.values(taxData)
          .filter((t) => t?.rest_base)
          .map((t) => ({ slug: t.slug, restBase: t.rest_base, name: t.name }));
        taxonomiesCache = list;
        dispatch({ type: 'SET_TAXONOMIES', payload: list });
      })
      .finally(() => {
        fetchingRef.current.tax = false;
        dispatch({ type: 'SET_LOADING', payload: false });
      });
  }, [isOpen, sourceEntity, selectedTag]);

  // ===== Fetch: Terms for a taxonomy (with caching) =====
  useEffect(() => {
    if (!isOpen || !taxonomy || !(sourceEntity === 'term' || selectedTag === 'term_list')) return;
    if (termsCache.has(taxonomy)) {
      dispatch({ type: 'SET_TERMS_FOR_TAX', taxonomy, terms: termsCache.get(taxonomy) });
      return;
    }
    if (fetchingRef.current.terms.has(taxonomy)) return;

    const taxObj =
      (taxonomiesCache || state.taxonomies || []).find((t) => t.slug === taxonomy) ||
      state.taxonomies.find((t) => t.slug === taxonomy);
    if (!taxObj?.restBase) return;

    dispatch({ type: 'SET_LOADING', payload: true });
    fetchingRef.current.terms.add(taxonomy);

    apiFetch({ path: `/wp/v2/${taxObj.restBase}?per_page=100&_fields=id,name,description,link` })
      .then((terms) => {
        termsCache.set(taxonomy, terms || []);
        dispatch({ type: 'SET_TERMS_FOR_TAX', taxonomy, terms: terms || [] });
      })
      .finally(() => {
        fetchingRef.current.terms.delete(taxonomy);
        dispatch({ type: 'SET_LOADING', payload: false });
      });
  }, [isOpen, taxonomy, sourceEntity, selectedTag, state.taxonomies]);

  // ===== Options builders =====
  const postOptions = useMemo(() => {
    const options = [{ label: __('Select a post', 'axcelersblocks'), value: '' }];
    Object.values(state.postsGrouped).forEach(({ label, restBase, posts }) => {
      if (posts?.length) {
        options.push({ label, value: '', disabled: true });
        options.push(
          ...posts.map((p) => ({
            label: `#${p.id} ${p?.title?.rendered || __('(no title)', 'axcelersblocks')}`,
            value: p.id.toString(),
            postType: restBase,
          }))
        );
      }
    });
    return options;
  }, [state.postsGrouped]);

  const taxonomyOptions = useMemo(() => {
    const list = taxonomiesCache || state.taxonomies || [];
    return [{ label: __('Select a taxonomy', 'axcelersblocks'), value: '' }].concat(
      list.map((t) => ({ label: t.name, value: t.slug }))
    );
  }, [state.taxonomies]);

  const termOptions = useMemo(() => {
    const list = termsCache.get(taxonomy) || state.termsByTax[taxonomy] || [];
    return [{ label: __('Select a term', 'axcelersblocks'), value: '' }].concat(
      list.map((term) => ({ label: `#${term.id} ${term.name}`, value: term.id.toString() }))
    );
  }, [taxonomy, state.termsByTax]);

  const getLinkOptions = () => {
    switch (selectedTag) {
      case 'term_list':
        return [
          { label: 'None', value: 'none' },
          { label: 'Post', value: 'post' },
          { label: 'Term', value: 'term' },
        ];
      case 'post_author':
			case 'author_avatar':
        return [
          { label: 'None', value: 'none' },
          { label: 'Post', value: 'post' },
          { label: 'Author', value: 'author' },
        ];
      case 'term_name':
      case 'term_description':
      case 'term_meta':
        return [
          { label: 'None', value: 'none' },
          { label: 'Term', value: 'term' },
        ];
			case 'acf_field':
				return (sourceEntity === 'term')
					? [
							{ label: 'None', value: 'none' },
							{ label: 'Term', value: 'term' },
						]
					: [
							{ label: 'None', value: 'none' },
							{ label: 'Post', value: 'post' },
						];
      default:
        return [
          { label: 'None', value: 'none' },
          { label: 'Post', value: 'post' },
        ];
    }
  };

  // ===== Tag builder =====
  const buildDynamicTag = () => {
    let tag = `{{${selectedTag}`;

    if (sourceEntity === 'post') {
      tag += ` entity:post`;
      if (sourceType === 'specific' && postId && postType) {
        tag += ` type:${postType} id:${postId}`;
      } else if (sourceType === 'current') {
        tag += ` source:current`;
      }
    } else if (sourceEntity === 'term') {
      tag += ` entity:term`;
      if (taxonomy) tag += ` tax:${taxonomy}`;
      if (termId) tag += ` term:${termId}`;
    }

    if (needsDateFormat && dateFormat) tag += `|format:${dateFormat}`;
    if (needsExcerptLen && typeof excerptLength === 'number') tag += `|length:${excerptLength}`;
    if (needsMetaKey && metaKey) tag += `|key:${metaKey}`;
    if (needsTermSeparator && typeof termSeparator === 'string') tag += `|sep:${termSeparator}`;
    if (needsACF && acfField) {
      tag += `|acf:${acfField}`;
      if (acfScope) tag += `|acfScope:${acfScope}`;
    }
    if (linkOption && linkOption !== 'none') tag += `|link:${linkOption}`;

    tag += '}}';
    return tag;
  };

  // ===== Insert =====
  const handleInsert = () => {
    const newTag = isButtonBlock ? selectedTag : buildDynamicTag();

    setAttributes({
      dynamicTag: newTag,
      ...(isButtonBlock ? { customLink: '' } : { content: '' }),
      selectedTag,
      sourceType,
      sourceEntity,
      postId,
      postType,
      taxonomy,
      termId,
      linkOption,
      dateFormat,
      excerptLength,
      metaKey,
      termSeparator,
      acfField,
      acfScope,
      required: state.requiredLocal,
    });

    if (!isButtonBlock) onInsert?.(newTag);
    onClose();
  };

  // ===== Render =====
  return isOpen ? (
    <Modal
      title={__('Dynamic Tags', 'axcelersblocks')}
      onRequestClose={onClose}
      className="axcelersblocks-dynamic-tag-modal"
    >
      {/* Tag */}
      <SelectControl
        label={__('Select a Dynamic Tag', 'axcelersblocks')}
        value={selectedTag}
        onChange={(value) => setAttributes({ selectedTag: value })}
        options={tagOptions}
      />

      {/* Entity */}
      <SelectControl
        label={__('Entity', 'axcelersblocks')}
        value={sourceEntity || 'post'}
        onChange={(value) => {
          setAttributes({
            sourceEntity: value,
            postId: '',
            postType: value === 'post' ? (postType || 'post') : '',
            taxonomy: value === 'term' ? (taxonomy || '') : (taxonomy || ''),
            termId: '',
          });
        }}
        options={[
          { label: __('Post', 'axcelersblocks'), value: 'post' },
          { label: __('Term', 'axcelersblocks'), value: 'term' },
        ]}
      />

      {/* Source (post only) */}
      {sourceEntity === 'post' && (
        <SelectControl
          label={__('Source', 'axcelersblocks')}
          value={sourceType}
          onChange={(value) => setAttributes({ sourceType: value, postId: value === 'current' ? '' : postId })}
          options={[
            { label: __('Current Post', 'axcelersblocks'), value: 'current' },
            { label: __('Specific Post', 'axcelersblocks'), value: 'specific' },
          ]}
        />
      )}

      {/* Specific post picker */}
      {sourceEntity === 'post' && sourceType === 'specific' && (
        <SelectControl
          label={__('Select Source Post', 'axcelersblocks')}
          value={postId || ''}
          onChange={(value) => {
            let selected = null;
            Object.values(state.postsGrouped).forEach(({ restBase, posts }) => {
              const match = posts.find((p) => p.id.toString() === value);
              if (match) selected = { postId: value, postType: restBase };
            });
            if (selected) setAttributes({ postId: selected.postId, postType: selected.postType });
          }}
          options={state.isLoading ? [{ label: __('Loading...', 'axcelersblocks'), value: '' }] : postOptions}
        />
      )}

      {/* Taxonomy picker (term entity or term_list tag) */}
      {needsTaxonomy && (
        <SelectControl
          label={__('Taxonomy', 'axcelersblocks')}
          value={taxonomy || ''}
          onChange={(value) => setAttributes({ taxonomy: value, termId: '' })}
          options={state.isLoading && !(taxonomiesCache || state.taxonomies)?.length
            ? [{ label: __('Loading...', 'axcelersblocks'), value: '' }]
            : taxonomyOptions}
        />
      )}

      {/* Term picker (term entity + specific term tags) */}
      {needsTermPick && (
        <SelectControl
          label={__('Term', 'axcelersblocks')}
          value={termId || ''}
          onChange={(value) => setAttributes({ termId: value })}
          options={state.isLoading && !(termsCache.get(taxonomy) || state.termsByTax[taxonomy])?.length
            ? [{ label: __('Loading...', 'axcelersblocks'), value: '' }]
            : termOptions}
        />
      )}

      {/* Per-tag options */}
      {selectedTag && (
        <>
          {needsDateFormat && (
            <TextControl
              label={__('Date Format (PHP format, blank = site default)', 'axcelersblocks')}
              value={dateFormat || ''}
              onChange={(value) => setAttributes({ dateFormat: value })}
              placeholder="F j, Y"
            />
          )}

          {needsExcerptLen && (
            <TextControl
              type="number"
              min={1}
              label={__('Excerpt Length (words)', 'axcelersblocks')}
              value={typeof excerptLength === 'number' ? excerptLength : 55}
              onChange={(value) => setAttributes({ excerptLength: Number(value) || 55 })}
            />
          )}

          {needsMetaKey && (
            <TextControl
              label={__('Meta Key', 'axcelersblocks')}
              value={metaKey || ''}
              onChange={(value) => setAttributes({ metaKey: value })}
              placeholder="e.g., custom_key"
            />
          )}

          {needsTermSeparator && (
            <TextControl
              label={__('Term Separator', 'axcelersblocks')}
              value={termSeparator ?? ', '}
              onChange={(value) => setAttributes({ termSeparator: value })}
              placeholder=", "
            />
          )}

          {needsACF && (
            <>
              <TextControl
                label={__('ACF Field (name or key)', 'axcelersblocks')}
                value={acfField || ''}
                onChange={(value) => setAttributes({ acfField: value })}
                placeholder="e.g., hero_title or field_123abc"
              />
              <SelectControl
                label={__('ACF Scope', 'axcelersblocks')}
                value={acfScope || 'entity'}
                onChange={(value) => setAttributes({ acfScope: value })}
                options={[
                  { label: __('Entity (current/specific post or term)', 'axcelersblocks'), value: 'entity' },
                  { label: __('Options Page', 'axcelersblocks'), value: 'options' },
                ]}
              />
            </>
          )}
        </>
      )}

      {/* Linking */}
      <SelectControl
        label={__('Link To', 'axcelersblocks')}
        value={linkOption || 'none'}
        onChange={(value) => setAttributes({ linkOption: value })}
        options={getLinkOptions()}
      />

      {/* Tag preview */}
      <TextControl
        label={__('Dynamic Tag to Insert', 'axcelersblocks')}
        value={buildDynamicTag()}
        readOnly
      />

      {/* Required toggle */}
      <ToggleControl
        label={__('Required to render', 'axcelersblocks')}
        checked={!!state.requiredLocal}
        onChange={(val) => dispatch({ type: 'SET_REQUIRED_LOCAL', payload: val })}
      />

      <Button
        variant="primary"
        onClick={handleInsert}
        style={{ marginTop: '16px' }}
        disabled={
          (needsMetaKey && !metaKey) ||
          (needsTermPick && !termId) ||
          (sourceEntity === 'post' && sourceType === 'specific' && !postId)
        }
      >
        {__('Insert dynamic tag', 'axcelersblocks')}
      </Button>
    </Modal>
  ) : null;
};

export default DynamicContentModal;
