const { createElement: el, Fragment, useState } = wp.element;
const { Button, Spinner, Notice } = wp.components;
const { useSelect, useDispatch, select: dataSelect } = wp.data;
const { __ } = wp.i18n;
const apiFetch = wp.apiFetch;
const { addFilter } = wp.hooks;
const { createHigherOrderComponent } = wp.compose;

const cfg = window.generatifyBlockEditor || { features: {}, restUrl: '', nonce: '' };
const features = cfg.features || {};

const SPARKLES = el(
  'span',
  { 'aria-hidden': 'true', style: { marginRight: '6px' } },
  '✨'
);

const baseButtonStyle = {
  width: '100%',
  justifyContent: 'center',
  background: '#155dfc',
  color: '#ffffff',
  borderRadius: '8px',
  border: 'none',
  marginTop: '12px',
};

const titleButtonStyle = {
  display: 'inline-flex',
  alignItems: 'center',
  background: '#155dfc',
  color: '#ffffff',
  borderRadius: '8px',
  border: 'none',
  fontSize: '12px',
  height: '28px',
  padding: '0 10px',
  marginBottom: '8px',
};

const helpTextStyle = {
  marginTop: '8px',
  fontSize: '12px',
  color: '#6b7280',
};

const errorStyle = { marginTop: '8px' };

function postRefs() {
  const editorSelect = dataSelect('core/editor');
  return {
    postId: editorSelect.getCurrentPostId(),
    title: editorSelect.getEditedPostAttribute('title') || '',
    content: editorSelect.getEditedPostAttribute('content') || '',
  };
}

function request(path, body) {
  return apiFetch({
    path: 'generatify/v1/' + path,
    method: 'POST',
    headers: { 'X-WP-Nonce': cfg.nonce },
    data: body,
  });
}

function GenerateButton({ label, busyLabel, helpWhenIdle, onClick, disabled, style }) {
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState(null);

  const handle = async () => {
    setError(null);
    setBusy(true);
    try {
      await onClick();
    } catch (e) {
      setError(e && e.message ? e.message : __('Generation failed.', 'generatify'));
    } finally {
      setBusy(false);
    }
  };

  const isDisabled = disabled || busy;
  const merged = Object.assign({}, style || baseButtonStyle, {
    opacity: isDisabled ? 0.7 : 1,
  });

  return el(
    Fragment,
    null,
    el(
      Button,
      {
        variant: 'primary',
        onClick: handle,
        disabled: isDisabled,
        style: merged,
      },
      busy
        ? el(Fragment, null, el(Spinner, null), ' ', busyLabel)
        : el(Fragment, null, SPARKLES, label)
    ),
    helpWhenIdle && !busy && !error
      ? el('p', { style: helpTextStyle }, helpWhenIdle)
      : null,
    error
      ? el(Notice, { status: 'error', isDismissible: true, onRemove: () => setError(null), style: errorStyle }, error)
      : null
  );
}

const MIN_CONTENT_LEN = 150 * 5;

function stripHtml(html) {
  const tmp = document.createElement('div');
  tmp.innerHTML = html;
  return (tmp.textContent || tmp.innerText || '').trim();
}

async function findOrCreateTerm(taxonomy, name, saveEntityRecord) {
  const restBase = taxonomy === 'post_tag' ? 'tags' : 'categories';
  const existing = await apiFetch({
    path: `/wp/v2/${restBase}?search=${encodeURIComponent(name)}&per_page=10`,
  });
  if (Array.isArray(existing)) {
    const match = existing.find(
      (t) => (t.name || '').toLowerCase() === name.toLowerCase()
    );
    if (match) {
      return match;
    }
  }
  return await saveEntityRecord('taxonomy', taxonomy, { name });
}

// --- Taxonomy buttons (inline inside Tags / Categories panels) ---

const withTaxonomyAugmentation = createHigherOrderComponent(
  (OriginalComponent) => (props) => {
    const taxonomy = props.slug;
    if (taxonomy !== 'post_tag' && taxonomy !== 'category') {
      return el(OriginalComponent, props);
    }
    if (taxonomy === 'post_tag' && !features.tags) {
      return el(OriginalComponent, props);
    }
    if (taxonomy === 'category' && !features.categories) {
      return el(OriginalComponent, props);
    }

    return el(
      Fragment,
      null,
      el(OriginalComponent, props),
      taxonomy === 'post_tag' ? el(TagButton, null) : el(CategoryButton, null)
    );
  },
  'withGeneratifyTaxonomyAugmentation'
);

addFilter(
  'editor.PostTaxonomyType',
  'generatify/post-taxonomy-type',
  withTaxonomyAugmentation
);

function TagButton() {
  const { editPost } = useDispatch('core/editor');
  const tagIds = useSelect(
    (sel) => sel('core/editor').getEditedPostAttribute('tags') || [],
    []
  );
  const { saveEntityRecord } = useDispatch('core');
  const { content } = useSelect(() => postRefs(), []);

  const idleHelp =
    (content || '').length < MIN_CONTENT_LEN
      ? __('Add more content to enable AI suggestions (approximately 150 words).', 'generatify')
      : null;

  return el(GenerateButton, {
    label: __('Suggest Tags', 'generatify'),
    busyLabel: __('Suggesting tags...', 'generatify'),
    helpWhenIdle: idleHelp,
    disabled: (content || '').length < MIN_CONTENT_LEN,
    onClick: async () => {
      const refs = postRefs();
      const data = await request('generate-tags', {
        postId: refs.postId,
        title: refs.title,
        content: stripHtml(refs.content),
      });
      const suggestions = Array.isArray(data && data.tags) ? data.tags : [];
      if (!suggestions.length) {
        throw new Error(__('No tag suggestions returned.', 'generatify'));
      }
      const existing = new Set(tagIds);
      for (const name of suggestions) {
        let term = await findOrCreateTerm('post_tag', name, saveEntityRecord);
        if (term && term.id) {
          existing.add(term.id);
        }
      }
      editPost({ tags: Array.from(existing) });
    },
  });
}

function CategoryButton() {
  const { editPost } = useDispatch('core/editor');
  const { content } = useSelect(() => postRefs(), []);
  const categoryIds = useSelect(
    (sel) => sel('core/editor').getEditedPostAttribute('categories') || [],
    []
  );

  const idleHelp =
    (content || '').length < MIN_CONTENT_LEN
      ? __('Add more content to enable AI suggestions (approximately 150 words).', 'generatify')
      : null;

  return el(GenerateButton, {
    label: __('Suggest Categories', 'generatify'),
    busyLabel: __('Suggesting category...', 'generatify'),
    helpWhenIdle: idleHelp,
    disabled: (content || '').length < MIN_CONTENT_LEN,
    onClick: async () => {
      const refs = postRefs();
      const data = await request('generate-categories', {
        postId: refs.postId,
        title: refs.title,
        content: stripHtml(refs.content),
      });
      const newId = data && data.categoryId ? Number(data.categoryId) : null;
      if (!newId) {
        throw new Error(__('No relevant category found among existing ones.', 'generatify'));
      }
      const next = Array.from(new Set([...(categoryIds || []), newId]));
      editPost({ categories: next });
    },
  });
}

// --- Featured Image button (inline inside Featured Image panel) ---

if (features.featuredImage) {
  addFilter(
    'editor.PostFeaturedImage',
    'generatify/post-featured-image',
    createHigherOrderComponent(
      (OriginalComponent) => (props) =>
        el(
          Fragment,
          null,
          el(OriginalComponent, props),
          el(FeaturedImageButton, null)
        ),
      'withGeneratifyFeaturedImage'
    )
  );
}

function FeaturedImageButton() {
  const { editPost } = useDispatch('core/editor');
  const { title, content } = useSelect(() => postRefs(), []);

  const ready = (title && title.trim().length > 0) || (content && content.trim().length > 0);
  const idleHelp = !ready ? __('Add a title or some content first.', 'generatify') : null;

  return el(GenerateButton, {
    label: __('Generate Featured Image', 'generatify'),
    busyLabel: __('Generating image...', 'generatify'),
    helpWhenIdle: idleHelp,
    disabled: !ready,
    onClick: async () => {
      const refs = postRefs();
      const data = await request('generate-featured-image', {
        postId: refs.postId,
        title: refs.title,
        content: stripHtml(refs.content),
      });
      if (data && data.attachmentId) {
        editPost({ featured_media: Number(data.attachmentId) });
      }
    },
  });
}

// --- Title button (mounted above the post title via DOM injection) ---
// `editor.PostTitle` is not a registered slot, so we inject directly.

if (features.title) {
  mountTitleButtonWhenReady();
}

function mountTitleButtonWhenReady() {
  const TITLE_SELECTORS = [
    '.editor-post-title',
    '.wp-block-post-title',
    '.editor-visual-editor__post-title-wrapper',
  ];
  const MOUNT_MARKER = 'data-generatify-title-mount';

  const findTitle = (doc) => {
    for (const sel of TITLE_SELECTORS) {
      const found = doc.querySelector(sel);
      if (found) return found;
    }
    return null;
  };

  const alreadyMounted = () => {
    if (document.querySelector(`[${MOUNT_MARKER}]`)) return true;
    const iframes = document.querySelectorAll('iframe');
    for (const f of iframes) {
      try {
        if (f.contentDocument && f.contentDocument.querySelector(`[${MOUNT_MARKER}]`)) {
          return true;
        }
      } catch (e) {}
    }
    return false;
  };

  const tryMount = () => {
    if (alreadyMounted()) return true;

    let target = findTitle(document);
    let targetDoc = document;

    if (!target) {
      const iframes = document.querySelectorAll('iframe');
      for (const iframe of iframes) {
        try {
          const iframeDoc = iframe.contentDocument;
          if (!iframeDoc) continue;
          const found = findTitle(iframeDoc);
          if (found) {
            target = found;
            targetDoc = iframeDoc;
            break;
          }
        } catch (e) {}
      }
    }

    if (!target || !target.parentNode) return false;

    const container = targetDoc.createElement('div');
    container.setAttribute(MOUNT_MARKER, '');
    container.style.padding = '0 0 4px';
    container.style.boxSizing = 'border-box';
    container.style.textAlign = 'left';

    const view = targetDoc.defaultView || window;
    const computed = view.getComputedStyle(target);
    // Mirror the title's horizontal layout so our button sits flush with it.
    if (computed) {
      if (computed.width && computed.width !== 'auto') {
        container.style.width = computed.width;
      }
      if (computed.maxWidth && computed.maxWidth !== 'none') {
        container.style.maxWidth = computed.maxWidth;
      }
      container.style.marginLeft = computed.marginLeft;
      container.style.marginRight = computed.marginRight;
      container.style.paddingLeft = computed.paddingLeft;
      container.style.paddingRight = computed.paddingRight;
    }

    target.parentNode.insertBefore(container, target);

    if (wp.element.createRoot) {
      wp.element.createRoot(container).render(el(TitleButton, null));
    } else {
      wp.element.render(el(TitleButton, null), container);
    }
    return true;
  };

  let attempts = 0;
  const maxAttempts = 60; // 60 * 500ms = 30s
  const interval = setInterval(() => {
    attempts += 1;
    if (tryMount() || attempts >= maxAttempts) {
      clearInterval(interval);
    }
  }, 500);
  // First attempt immediately
  tryMount();
}

function TitleButton() {
  const { editPost } = useDispatch('core/editor');
  const { content } = useSelect(() => postRefs(), []);

  const idleHelp =
    (content || '').length < MIN_CONTENT_LEN
      ? __('Add more content to enable AI suggestions (approximately 150 words).', 'generatify')
      : null;

  return el(GenerateButton, {
    label: __('Generate Title', 'generatify'),
    busyLabel: __('Generating title...', 'generatify'),
    helpWhenIdle: idleHelp,
    disabled: (content || '').length < MIN_CONTENT_LEN,
    style: titleButtonStyle,
    onClick: async () => {
      const refs = postRefs();
      const data = await request('generate-title', {
        postId: refs.postId,
        title: refs.title,
        content: stripHtml(refs.content),
      });
      if (data && data.title) {
        editPost({ title: String(data.title) });
      }
    },
  });
}
