/**
 * URL Changer Tool
 *
 * Permanently rewrites internal links when URLs change, instead of leaving
 * them leaking equity through redirect hops. Apply/revert run as time-boxed
 * steps driven from this page (no cron dependency). Every change is
 * journaled per link, so rules are fully revertible.
 *
 * @package
 * @since   1.0.0
 */

import { useCallback, useEffect, useRef, useState } from '@wordpress/element';
import { __, sprintf } from '@wordpress/i18n';
import apiFetch from '@wordpress/api-fetch';
import { Alert, Button, Card, CardBody, CardHeader, Input, Spinner, Toggle } from '../../components/ui';

const TEXT_DOMAIN = 'prorank-seo';
const BASE = '/prorank-seo/v1/linking/url-changer';

const STATUS_STYLES = {
  pending: { background: '#fff7ed', color: '#b45309' },
  applied: { background: '#ecfdf3', color: '#166534' },
  reverted: { background: '#f3f4f6', color: '#374151' },
};

const UrlChangerTool = () => {
  const [rules, setRules] = useState([]);
  const [candidates, setCandidates] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState('');
  const [notice, setNotice] = useState('');
  const [oldUrl, setOldUrl] = useState('');
  const [newUrl, setNewUrl] = useState('');
  const [wildcard, setWildcard] = useState(false);
  const [creating, setCreating] = useState(false);
  const [workingRuleId, setWorkingRuleId] = useState(0);
  const [recoverableCount, setRecoverableCount] = useState(0);
  const [importingRecoverable, setImportingRecoverable] = useState(false);
  const stopRequested = useRef(false);

  const loadRules = useCallback(async () => {
    const response = await apiFetch({ path: `${BASE}/rules` });
    setRules(Array.isArray(response?.rules) ? response.rules : []);
  }, []);

  const loadRecoverable = useCallback(async () => {
    try {
      const response = await apiFetch({ path: `${BASE}/import-recoverable` });
      setRecoverableCount(Number(response?.count || 0));
    } catch (e) {
      // Endpoint unavailable — leave at 0.
    }
  }, []);

  const importRecoverable = async () => {
    setImportingRecoverable(true);
    setError('');
    setNotice('');
    try {
      const result = await apiFetch({ path: `${BASE}/import-recoverable`, method: 'POST' });
      await loadRules();
      await loadRecoverable();
      setNotice(
        sprintf(
          /* translators: %d: number of fix rules created */
          __('Created %d fix rule(s) from redirect/case-mismatch links. Click Apply on each to rewrite them to the canonical URL.', TEXT_DOMAIN),
          Number(result?.created || 0)
        )
      );
    } catch (e) {
      setError(e?.message || __('Could not import recoverable links.', TEXT_DOMAIN));
    } finally {
      setImportingRecoverable(false);
    }
  };

  const loadCandidates = useCallback(async (refresh = false) => {
    const response = await apiFetch({ path: `${BASE}/redirect-candidates${refresh ? '?refresh=1' : ''}` });
    setCandidates(Array.isArray(response?.candidates) ? response.candidates : []);
  }, []);

  useEffect(() => {
    (async () => {
      try {
        await loadRules();
      } catch (e) {
        setError(e?.message || __('Failed to load URL changer data.', TEXT_DOMAIN));
      } finally {
        setLoading(false);
      }
    })();
  }, [loadRules]);

  // The stale-redirect scan runs LIKE queries across every post, so it must
  // not block the initial render — load it after the page is interactive.
  useEffect(() => {
    loadCandidates().catch(() => {});
    loadRecoverable().catch(() => {});
  }, [loadCandidates, loadRecoverable]);

  const createRule = async (old_url, new_url, isWildcard) => {
    setError('');
    setNotice('');
    setCreating(true);
    try {
      await apiFetch({
        path: `${BASE}/rules`,
        method: 'POST',
        data: { old_url, new_url, wildcard: isWildcard },
      });
      setOldUrl('');
      setNewUrl('');
      setWildcard(false);
      await loadRules();
      setNotice(__('Rule created. Click Apply to update links.', TEXT_DOMAIN));
    } catch (e) {
      setError(e?.message || __('Could not create rule.', TEXT_DOMAIN));
    } finally {
      setCreating(false);
    }
  };

  const runSteps = async (ruleId, action) => {
    setError('');
    setNotice('');
    setWorkingRuleId(ruleId);
    stopRequested.current = false;
    try {
      let guard = 0;
      let result = null;
      while (!stopRequested.current && guard < 500) {
        guard += 1;
        result = await apiFetch({ path: `${BASE}/rules/${ruleId}/${action}`, method: 'POST' });
        setRules((prev) => prev.map((rule) => (rule.id === ruleId ? { ...rule, ...result, done: undefined } : rule)));
        if (!result || result.done === true) {
          break;
        }
      }
      await loadRules();
      if (result?.done === true) {
        setNotice(
          action === 'apply'
            ? sprintf(
                /* translators: 1: links updated, 2: posts updated */
                __('Done — %1$d link(s) updated across %2$d post(s).', TEXT_DOMAIN),
                result.links_updated || 0,
                result.posts_updated || 0
              )
            : __('All changes for this rule were reverted.', TEXT_DOMAIN)
        );
        loadCandidates(true).catch(() => {});
      }
    } catch (e) {
      setError(e?.message || __('Operation failed.', TEXT_DOMAIN));
    } finally {
      setWorkingRuleId(0);
    }
  };

  const deleteRule = async (ruleId) => {
    if (!window.confirm(__('Delete this rule?', TEXT_DOMAIN))) {
      return;
    }
    setError('');
    try {
      await apiFetch({ path: `${BASE}/rules/${ruleId}`, method: 'DELETE' });
      await loadRules();
    } catch (e) {
      setError(e?.message || __('Could not delete rule.', TEXT_DOMAIN));
    }
  };

  if (loading) {
    return (
      <div style={{ display: 'flex', justifyContent: 'center', padding: '48px' }}>
        <Spinner />
      </div>
    );
  }

  return (
    <div className="prorank-url-changer">
      {error && <Alert variant="error">{error}</Alert>}
      {notice && <Alert variant="success">{notice}</Alert>}

      {recoverableCount > 0 && (
        <Card>
          <CardBody>
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: '12px', flexWrap: 'wrap' }}>
              <div style={{ minWidth: 0, flex: 1 }}>
                <strong>
                  {sprintf(
                    /* translators: %d: number of recoverable links */
                    __('%d internal link(s) point to redirecting / mis-cased URLs', TEXT_DOMAIN),
                    recoverableCount
                  )}
                </strong>
                <div style={{ fontSize: '13px', color: '#6b7280', marginTop: '2px' }}>
                  {__('The last scan found links that resolve only via a redirect (wrong case, trailing characters, etc.). These leak link equity and read as orphan pages to search engines. Create fix rules to rewrite them to the canonical URL.', TEXT_DOMAIN)}
                </div>
              </div>
              <Button variant="primary" disabled={importingRecoverable} onClick={importRecoverable}>
                {importingRecoverable
                  ? __('Creating fixes…', TEXT_DOMAIN)
                  : sprintf(
                      /* translators: %d: number of links */
                      __('Create %d Fix Rules', TEXT_DOMAIN),
                      recoverableCount
                    )}
              </Button>
            </div>
          </CardBody>
        </Card>
      )}

      <Card>
        <CardHeader>
          <h3>{__('Change a URL Everywhere', TEXT_DOMAIN)}</h3>
        </CardHeader>
        <CardBody>
          <p style={{ marginTop: 0, color: '#6b7280' }}>
            {__('Rewrites every internal link pointing at the old URL — in post content, excerpts, shortcode URL attributes, and Elementor / Beaver Builder data. Each changed link is journaled and marked, so the rule can be fully reverted.', TEXT_DOMAIN)}
          </p>
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '12px', alignItems: 'end' }}>
            <Input
              label={__('Old URL', TEXT_DOMAIN)}
              value={oldUrl}
              onChange={(value) => setOldUrl(typeof value === 'string' ? value : value?.target?.value ?? '')}
              placeholder="https://example.com/old-page/"
            />
            <Input
              label={__('New URL', TEXT_DOMAIN)}
              value={newUrl}
              onChange={(value) => setNewUrl(typeof value === 'string' ? value : value?.target?.value ?? '')}
              placeholder="https://example.com/new-page/"
            />
          </div>
          <div style={{ display: 'flex', alignItems: 'center', gap: '16px', marginTop: '12px', flexWrap: 'wrap' }}>
            <Toggle
              checked={wildcard}
              onChange={setWildcard}
              label={__('Prefix match (rewrite everything under the old URL)', TEXT_DOMAIN)}
            />
            <Button
              variant="primary"
              disabled={creating || !oldUrl.trim() || !newUrl.trim()}
              onClick={() => createRule(oldUrl.trim(), newUrl.trim(), wildcard)}
            >
              {creating ? __('Creating…', TEXT_DOMAIN) : __('Create Rule', TEXT_DOMAIN)}
            </Button>
          </div>
        </CardBody>
      </Card>

      {candidates.length > 0 && (
        <Card>
          <CardHeader>
            <h3>{__('Redirects With Stale Internal Links', TEXT_DOMAIN)}</h3>
          </CardHeader>
          <CardBody>
            <p style={{ marginTop: 0, color: '#6b7280' }}>
              {__('These active redirects still have internal links pointing at the old URL. Updating the links removes the redirect hop.', TEXT_DOMAIN)}
            </p>
            {candidates.map((candidate) => (
              <div
                key={candidate.redirect_id}
                style={{
                  display: 'flex',
                  justifyContent: 'space-between',
                  alignItems: 'center',
                  gap: '12px',
                  padding: '10px 0',
                  borderBottom: '1px solid #f3f4f6',
                  flexWrap: 'wrap',
                }}
              >
                <div style={{ minWidth: 0, flex: 1 }}>
                  <div style={{ fontWeight: 600, wordBreak: 'break-all' }}>{candidate.source_url}</div>
                  <div style={{ fontSize: '12px', color: '#6b7280', wordBreak: 'break-all' }}>
                    → {candidate.target_url}
                  </div>
                </div>
                <div style={{ fontSize: '12px', color: '#b45309', whiteSpace: 'nowrap' }}>
                  {sprintf(
                    /* translators: %s: number of posts (may be "50+") */
                    __('%s post(s) still link here', TEXT_DOMAIN),
                    candidate.stale_posts_capped ? `${candidate.stale_posts}+` : String(candidate.stale_posts)
                  )}
                </div>
                <Button
                  variant="secondary"
                  disabled={creating}
                  onClick={() => createRule(candidate.source_url, candidate.target_url, false)}
                >
                  {__('Create Update Rule', TEXT_DOMAIN)}
                </Button>
              </div>
            ))}
          </CardBody>
        </Card>
      )}

      <Card>
        <CardHeader>
          <h3>{__('Rules', TEXT_DOMAIN)}</h3>
        </CardHeader>
        <CardBody>
          {rules.length === 0 && (
            <p style={{ color: '#6b7280' }}>{__('No URL change rules yet.', TEXT_DOMAIN)}</p>
          )}
          {rules.map((rule) => {
            const badge = STATUS_STYLES[rule.status] || STATUS_STYLES.pending;
            const working = workingRuleId === rule.id;
            return (
              <div
                key={rule.id}
                style={{
                  display: 'flex',
                  justifyContent: 'space-between',
                  alignItems: 'center',
                  gap: '12px',
                  padding: '12px 0',
                  borderBottom: '1px solid #f3f4f6',
                  flexWrap: 'wrap',
                }}
              >
                <div style={{ minWidth: 0, flex: 1 }}>
                  <div style={{ fontWeight: 600, wordBreak: 'break-all' }}>
                    {rule.old_url}
                    {rule.wildcard ? '*' : ''}
                  </div>
                  <div style={{ fontSize: '12px', color: '#6b7280', wordBreak: 'break-all' }}>→ {rule.new_url}</div>
                  {rule.links_updated > 0 && (
                    <div style={{ fontSize: '12px', color: '#374151', marginTop: '4px' }}>
                      {sprintf(
                        /* translators: 1: links updated, 2: posts updated */
                        __('%1$d link(s) in %2$d post(s)', TEXT_DOMAIN),
                        rule.links_updated,
                        rule.posts_updated
                      )}
                    </div>
                  )}
                </div>
                <span
                  style={{
                    ...badge,
                    padding: '4px 10px',
                    borderRadius: '9999px',
                    fontSize: '11px',
                    fontWeight: 600,
                    whiteSpace: 'nowrap',
                  }}
                >
                  {rule.status}
                </span>
                <div style={{ display: 'flex', gap: '8px', flexWrap: 'wrap' }}>
                  {rule.status === 'pending' && (
                    <Button variant="primary" disabled={workingRuleId !== 0} onClick={() => runSteps(rule.id, 'apply')}>
                      {working ? __('Applying…', TEXT_DOMAIN) : __('Apply', TEXT_DOMAIN)}
                    </Button>
                  )}
                  {rule.status === 'applied' && (
                    <Button
                      variant="secondary"
                      disabled={workingRuleId !== 0}
                      onClick={() => runSteps(rule.id, 'revert')}
                    >
                      {working ? __('Reverting…', TEXT_DOMAIN) : __('Revert', TEXT_DOMAIN)}
                    </Button>
                  )}
                  {rule.status !== 'applied' && rule.links_updated === 0 && (
                    <Button variant="secondary" disabled={workingRuleId !== 0} onClick={() => deleteRule(rule.id)}>
                      {__('Delete', TEXT_DOMAIN)}
                    </Button>
                  )}
                </div>
              </div>
            );
          })}
          {workingRuleId !== 0 && (
            <p style={{ fontSize: '12px', color: '#6b7280', marginTop: '12px' }}>
              {__('Keep this window open — changes run in short batches from this page.', TEXT_DOMAIN)}
            </p>
          )}
        </CardBody>
      </Card>
    </div>
  );
};

export default UrlChangerTool;
