/**
 * Headline Analyzer Panel
 *
 * Google-aligned headline analysis based on Search Central guidance.
 * Analyzes rewrite risk, content match, uniqueness, stuffing, and schema alignment.
 *
 * @see https://developers.google.com/search/docs/appearance/title-link
 */

import { debounce } from 'lodash';
import './headline-analyzer-panel.css';

const PRORANK_EDITOR_META_SYNC_EVENT = 'prorank:editor-meta-sync';

const HeadlineAnalyzerPanel = ({ postId }) => {
  const { useState, useEffect, useCallback, useMemo, useRef } = window.wp.element;
  const {
    __ = (text) => text,
    sprintf = (format, ...args) => [format, ...args].join(' '),
  } = window.wp?.i18n || {};
  const apiFetch = window.wp.apiFetch;
  const { useSelect } = window.wp.data;
  const { Spinner, Button } = window.wp.components;

  const [analysis, setAnalysis] = useState(null);
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState(null);
  const [seoTitleOverride, setSeoTitleOverride] = useState('');
  const latestRequestKeyRef = useRef('');
  const [expandedSections, setExpandedSections] = useState({
    rewrite: true,
    content: false,
    uniqueness: false,
    stuffing: false,
    schema: false,
  });

  const { title } = useSelect((select) => {
    const editor = select('core/editor');
    return {
      title: editor.getEditedPostAttribute('title') || '',
    };
  }, []);

  useEffect(() => {
    if (!postId) {
      setSeoTitleOverride('');
      return undefined;
    }

    let isMounted = true;

    apiFetch({ path: `/prorank-seo/v1/meta/${postId}`, method: 'GET' })
      .then((response) => {
        if (isMounted) {
          setSeoTitleOverride(response?.data?.seo_title || '');
        }
      })
      .catch(() => {
        if (isMounted) {
          setSeoTitleOverride('');
        }
      });

    return () => {
      isMounted = false;
    };
  }, [postId, apiFetch]);

  useEffect(() => {
    const handleMetaSync = (event) => {
      const detail = event?.detail || {};
      if (detail.postId !== postId) {
        return;
      }

      if (Object.prototype.hasOwnProperty.call(detail, 'seoTitle')) {
        setSeoTitleOverride(detail.seoTitle || '');
      }
    };

    window.addEventListener(PRORANK_EDITOR_META_SYNC_EVENT, handleMetaSync);
    return () => window.removeEventListener(PRORANK_EDITOR_META_SYNC_EVENT, handleMetaSync);
  }, [postId]);

  const effectiveTitle = seoTitleOverride || title;
  const hasSeoTitleOverride = Boolean(seoTitleOverride && seoTitleOverride.trim());
  const currentRequestKey = `${postId || 0}:${effectiveTitle || ''}`;

  const analyzeHeadline = useCallback(
    debounce(async (titleToAnalyze, currentPostId, requestKey) => {
      if (!titleToAnalyze || titleToAnalyze.length < 3) {
        setAnalysis(null);
        return;
      }

      setIsLoading(true);
      setError(null);

      try {
        const response = await apiFetch({
          path: '/prorank-seo/v1/headline-analyzer/analyze',
          method: 'POST',
          data: {
            title: titleToAnalyze,
            post_id: currentPostId || 0,
          },
        });

        if (response?.success && response?.data) {
          if (latestRequestKeyRef.current !== requestKey) {
            return;
          }
          setAnalysis(response.data);
        } else {
          if (latestRequestKeyRef.current !== requestKey) {
            return;
          }
          setError(__('Failed to analyze headline', 'prorank-seo'));
        }
      } catch (err) {
        if (latestRequestKeyRef.current !== requestKey) {
          return;
        }
        console.error('Headline analysis error:', err);
        setError(err?.message || __('Analysis failed', 'prorank-seo'));
      } finally {
        if (latestRequestKeyRef.current === requestKey) {
          setIsLoading(false);
        }
      }
    }, 500),
    []
  );

  useEffect(() => {
    latestRequestKeyRef.current = currentRequestKey;
    setAnalysis(null);
    setError(null);
    analyzeHeadline.cancel?.();
    analyzeHeadline(effectiveTitle, postId, currentRequestKey);
  }, [effectiveTitle, postId, currentRequestKey, analyzeHeadline]);

  useEffect(() => () => analyzeHeadline.cancel?.(), [analyzeHeadline]);

  const toggleSection = (section) => {
    setExpandedSections((prev) => ({
      ...prev,
      [section]: !prev[section],
    }));
  };

  const getScoreColor = (score) => {
    if (score >= 80) return '#22c55e'; // Green
    if (score >= 60) return '#f59e0b'; // Orange
    return '#ef4444'; // Red
  };

  const getRiskLabel = (level) => {
    switch (level) {
      case 'low':
        return { text: __('Low Risk', 'prorank-seo'), color: '#22c55e' };
      case 'medium':
        return { text: __('Medium Risk', 'prorank-seo'), color: '#f59e0b' };
      case 'high':
        return { text: __('High Risk', 'prorank-seo'), color: '#ef4444' };
      default:
        return { text: __('Unknown', 'prorank-seo'), color: '#6b7280' };
    }
  };

  const getSeverityIcon = (severity) => {
    switch (severity) {
      case 'high':
        return '!';
      case 'medium':
        return '!';
      case 'low':
        return 'i';
      default:
        return '?';
    }
  };

  const getSeverityColor = (severity) => {
    switch (severity) {
      case 'high':
        return '#ef4444';
      case 'medium':
        return '#f59e0b';
      case 'low':
        return '#3b82f6';
      default:
        return '#6b7280';
    }
  };

  const normalizeIssue = (issue, fallbackSeverity = 'low') => {
    if (!issue) return null;
    if (typeof issue === 'string') {
      return { message: issue, severity: fallbackSeverity };
    }

    if (typeof issue === 'object') {
      return {
        message: issue.message || '',
        severity: issue.severity || fallbackSeverity,
      };
    }

    return null;
  };

  const normalizedAnalysis = useMemo(() => {
    if (!analysis) {
      return null;
    }

    const lengthData = analysis.length || {};
    const chars = Number(lengthData.chars ?? lengthData.length ?? effectiveTitle.length ?? 0);
    // When the server did not measure pixel width, fall back to a rough
    // chars-based estimate — and flag it so the UI labels it as such.
    const hasServerPixelWidth = lengthData.pixel_width !== undefined && lengthData.pixel_width !== null;
    const pixelWidth = Number(hasServerPixelWidth ? lengthData.pixel_width : Math.round(chars * 9.2));
    const truncated = typeof lengthData.truncated === 'boolean'
      ? lengthData.truncated
      : lengthData.status === 'too_long' || chars > 60 || pixelWidth > 580;

    const overallScore = Number(analysis.overall_score || 0);
    const derivedRiskLevel = overallScore >= 80 ? 'low' : overallScore >= 60 ? 'medium' : 'high';

    const rewriteIssues = [
      ...(Array.isArray(analysis.issues) ? analysis.issues : []),
      ...(lengthData.status && lengthData.status !== 'good' && lengthData.message
        ? [{ message: lengthData.message, severity: lengthData.score < 50 ? 'high' : 'medium' }]
        : []),
    ]
      .map((issue) => normalizeIssue(issue, 'low'))
      .filter(Boolean);

    const contentScore = Number(analysis.content_match?.score ?? 0);
    const contentIssues = (Array.isArray(analysis.content_match?.issues) ? analysis.content_match.issues : [])
      .map((issue) => normalizeIssue(issue, 'low'))
      .filter(Boolean);

    const uniquenessIssues = (Array.isArray(analysis.uniqueness?.issues) && analysis.uniqueness.issues.length > 0
      ? analysis.uniqueness.issues
      : (analysis.uniqueness?.recommendations || [])
    )
      .map((issue) => normalizeIssue(issue, 'medium'))
      .filter(Boolean);

    const stuffingScore = Number(analysis.stuffing?.score ?? 0);
    const stuffingIssues = (Array.isArray(analysis.stuffing?.issues) ? analysis.stuffing.issues : [])
      .map((issue) => normalizeIssue(issue, 'low'))
      .filter(Boolean);

    const suggestions = (Array.isArray(analysis.suggestions) && analysis.suggestions.length > 0
      ? analysis.suggestions
      : (analysis.recommendations || [])
    )
      .map((suggestion) => {
        if (typeof suggestion === 'string') {
          return { message: suggestion, priority: 'medium' };
        }
        if (suggestion && typeof suggestion === 'object') {
          return {
            message: suggestion.message || '',
            priority: suggestion.priority || 'medium',
          };
        }
        return null;
      })
      .filter(Boolean);

    return {
      length: {
        chars,
        pixel_width: pixelWidth,
        pixel_width_estimated: !hasServerPixelWidth,
        truncated,
      },
      rewrite_risk: {
        level: analysis.rewrite_risk?.level || derivedRiskLevel,
        issues: (Array.isArray(analysis.rewrite_risk?.issues) && analysis.rewrite_risk.issues.length > 0)
          ? analysis.rewrite_risk.issues.map((issue) => normalizeIssue(issue, 'low')).filter(Boolean)
          : rewriteIssues,
      },
      content_match: {
        score: Math.max(0, Math.min(100, Math.round(contentScore))),
        issues: contentIssues,
        precision: Number(analysis.content_match?.precision ?? 0),
        recall: Number(analysis.content_match?.recall ?? 0),
        applicable: Boolean(analysis.content_match?.applicable),
      },
      uniqueness: {
        score: Number(analysis.uniqueness?.score ?? 100),
        issues: uniquenessIssues,
        duplicates: Array.isArray(analysis.uniqueness?.duplicates) ? analysis.uniqueness.duplicates : [],
      },
      stuffing: {
        score: Math.max(0, Math.min(100, Math.round(stuffingScore))),
        issues: stuffingIssues,
      },
      schema: analysis.schema || null,
      suggestions,
    };
  }, [analysis, effectiveTitle]);

  const getScoreVariant = (s) => (s >= 80 ? '' : s >= 60 ? ' warn' : ' bad');

  const ScoreCircle = ({ score, label }) => (
    <div className="headline-score-block">
      <div className={`headline-score-num${getScoreVariant(score)}`}>{score}</div>
      <div className="headline-score-suffix">/ 100</div>
      {label && <div className="headline-score-label">{label}</div>}
    </div>
  );

  const CheckSection = ({ title, score, level, issues, expanded, onToggle, children }) => {
    const riskInfo = level ? getRiskLabel(level) : null;

    return (
      <div className="headline-check-section">
        <button
          className="headline-check-header"
          onClick={onToggle}
          type="button"
        >
          <div className="headline-check-title">
            <span className="headline-check-arrow">{expanded ? '▼' : '▶'}</span>
            <span>{title}</span>
          </div>
          <div className="headline-check-meta">
            {riskInfo && (
              <span className={`headline-risk-badge headline-risk-badge--${level}`}>
                {riskInfo.text}
              </span>
            )}
            {!riskInfo && score !== undefined && (
              <span className={`headline-score-badge${getScoreVariant(score)}`}>
                {score}
              </span>
            )}
          </div>
        </button>
        {expanded && (
          <div className="headline-check-content">
            {issues && issues.length > 0 && (
              <ul className="headline-issues-list">
                {issues.map((issue, index) => (
                  <li
                    key={index}
                    className={`headline-issue-item headline-issue-item--${issue.severity || 'low'}`}
                  >
                    <span className={`headline-issue-icon headline-issue-icon--${issue.severity || 'low'}`}>
                      {getSeverityIcon(issue.severity)}
                    </span>
                    <span className="headline-issue-message">{issue.message}</span>
                  </li>
                ))}
              </ul>
            )}
            {(!issues || issues.length === 0) && (
              <p className="headline-no-issues">
                {__('No issues detected', 'prorank-seo')}
              </p>
            )}
            {children}
          </div>
        )}
      </div>
    );
  };

  if (!effectiveTitle || effectiveTitle.length < 3) {
    return (
      <div className="headline-analyzer-panel">
        <div className="headline-empty-state">
          <p>{__('Enter a title to analyze', 'prorank-seo')}</p>
        </div>
      </div>
    );
  }

  if (isLoading && !analysis) {
    return (
      <div className="headline-analyzer-panel">
        <div className="headline-loading">
          <Spinner />
          <p>{__('Analyzing headline...', 'prorank-seo')}</p>
        </div>
      </div>
    );
  }

  if (error && !analysis) {
    return (
      <div className="headline-analyzer-panel">
        <div className="headline-error">
          <p>{error}</p>
          <Button
            isSecondary
            onClick={() => {
              latestRequestKeyRef.current = currentRequestKey;
              setAnalysis(null);
              setError(null);
              analyzeHeadline.cancel?.();
              analyzeHeadline(effectiveTitle, postId, currentRequestKey);
            }}
          >
            {__('Retry', 'prorank-seo')}
          </Button>
        </div>
      </div>
    );
  }

  if (!analysis || !normalizedAnalysis) {
    return null;
  }

  return (
    <div className="headline-analyzer-panel">
      {/* Overall Score */}
      <div className="headline-overall">
        <ScoreCircle
          score={analysis.overall_score}
          size={70}
          label={__('Overall', 'prorank-seo')}
        />
        <div className="headline-overall-info">
          <h4>{__('Google Alignment', 'prorank-seo')}</h4>
          <p className="headline-overall-desc">
            {analysis.overall_score >= 80
              ? __('Low rewrite risk', 'prorank-seo')
              : analysis.overall_score >= 60
              ? __('Some issues to address', 'prorank-seo')
              : __('High rewrite risk', 'prorank-seo')}
          </p>
        </div>
        {isLoading && <Spinner className="headline-refresh-spinner" />}
      </div>

      {/* Language Warning */}
      {analysis.language_warning && (
        <div className="headline-language-warning">
          <span className="headline-warning-icon">!</span>
          <span>
            {__('Non-Latin script detected. Analysis uses English tokenization only.', 'prorank-seo')}
          </span>
        </div>
      )}

      <div className="headline-title-source">
        <div className="headline-title-source-label">
          {hasSeoTitleOverride
            ? __('Analyzing SEO title override', 'prorank-seo')
            : __('Analyzing post title', 'prorank-seo')}
        </div>
        <div className="headline-title-source-value">{effectiveTitle}</div>
        {hasSeoTitleOverride && title && title !== effectiveTitle && (
          <div className="headline-title-source-note">
            {__('Post title:', 'prorank-seo')} {title}
          </div>
        )}
      </div>

      {/* Length Info */}
      <div className="headline-length-info">
        <div className="headline-length-item">
          <span className="headline-length-label">{__('Characters', 'prorank-seo')}</span>
          <span className="headline-length-value">{normalizedAnalysis.length.chars || 0}</span>
        </div>
        <div className="headline-length-item">
          <span className="headline-length-label">{__('Pixel Width', 'prorank-seo')}</span>
          <span className={`headline-length-value${normalizedAnalysis.length.truncated ? ' bad' : ''}`}>
            {normalizedAnalysis.length.pixel_width_estimated
              ? sprintf(
                  /* translators: %d: estimated pixel width */
                  __('~%dpx (est.)', 'prorank-seo'),
                  normalizedAnalysis.length.pixel_width || 0
                )
              : `${normalizedAnalysis.length.pixel_width || 0}px`}
            {normalizedAnalysis.length.truncated && ' ⚠'}
          </span>
        </div>
      </div>

      {/* Check Sections */}
      <div className="headline-checks">
        <CheckSection
          title={__('Rewrite Risk', 'prorank-seo')}
          level={normalizedAnalysis.rewrite_risk.level}
          issues={normalizedAnalysis.rewrite_risk.issues}
          expanded={expandedSections.rewrite}
          onToggle={() => toggleSection('rewrite')}
        />

        <CheckSection
          title={__('Content Match', 'prorank-seo')}
          score={normalizedAnalysis.content_match.score}
          issues={normalizedAnalysis.content_match.issues}
          expanded={expandedSections.content}
          onToggle={() => toggleSection('content')}
        >
          {normalizedAnalysis.content_match?.applicable && (
            <div className="headline-content-stats">
              <div className="headline-stat">
                <span>{__('Title Match', 'prorank-seo')}</span>
                <span>{Math.round(normalizedAnalysis.content_match.precision * 100)}%</span>
              </div>
              <div className="headline-stat">
                <span>{__('Content Recall', 'prorank-seo')}</span>
                <span>{Math.round(normalizedAnalysis.content_match.recall * 100)}%</span>
              </div>
            </div>
          )}
        </CheckSection>

        <CheckSection
          title={__('Uniqueness', 'prorank-seo')}
          score={normalizedAnalysis.uniqueness.score}
          issues={normalizedAnalysis.uniqueness.issues}
          expanded={expandedSections.uniqueness}
          onToggle={() => toggleSection('uniqueness')}
        >
          {normalizedAnalysis.uniqueness.duplicates.length > 0 && (
            <div className="headline-duplicates">
              <p className="headline-duplicates-label">
                {__('Duplicate titles found:', 'prorank-seo')}
              </p>
              <ul className="headline-duplicates-list">
                {normalizedAnalysis.uniqueness.duplicates.slice(0, 3).map((dup, i) => (
                  <li key={i}>
                    <a href={dup.url} target="_blank" rel="noopener noreferrer">
                      {dup.title}
                    </a>
                  </li>
                ))}
              </ul>
            </div>
          )}
        </CheckSection>

        <CheckSection
          title={__('Stuffing Check', 'prorank-seo')}
          score={normalizedAnalysis.stuffing.score}
          issues={normalizedAnalysis.stuffing.issues}
          expanded={expandedSections.stuffing}
          onToggle={() => toggleSection('stuffing')}
        />

        {normalizedAnalysis.schema?.applicable && (
          <CheckSection
            title={__('Schema Alignment', 'prorank-seo')}
            score={normalizedAnalysis.schema?.score}
            issues={normalizedAnalysis.schema?.issues}
            expanded={expandedSections.schema}
            onToggle={() => toggleSection('schema')}
          >
            {normalizedAnalysis.schema?.schema_headline && (
              <div className="headline-schema-info">
                <span className="headline-schema-label">
                  {__('Schema headline:', 'prorank-seo')}
                </span>
                <span className="headline-schema-value">
                  {normalizedAnalysis.schema.schema_headline}
                </span>
              </div>
            )}
          </CheckSection>
        )}
      </div>

      {/* Suggestions */}
      {normalizedAnalysis.suggestions && normalizedAnalysis.suggestions.length > 0 && (
        <div className="headline-suggestions">
          <h4>{__('Suggestions', 'prorank-seo')}</h4>
          <ul>
            {normalizedAnalysis.suggestions.map((suggestion, index) => (
              <li
                key={index}
                className={`headline-suggestion headline-suggestion-${suggestion.priority}`}
              >
                {suggestion.message}
              </li>
            ))}
          </ul>
        </div>
      )}

      {/* Info Footer */}
      <div className="headline-info-footer">
        <a
          href="https://developers.google.com/search/docs/appearance/title-link"
          target="_blank"
          rel="noopener noreferrer"
        >
          {__('Learn about Google title links', 'prorank-seo')} →
        </a>
      </div>
    </div>
  );
};

export default HeadlineAnalyzerPanel;
