import { ChevronRight, ArrowRight, BookOpen } from 'lucide-react';

import { memo, useCallback, useState } from 'react';

import { Link } from '@inertiajs/react';

import MetricDelta from '@/Components/Shared/MetricDelta';
import { Badge } from '@/Components/ui/badge';
import { formatDecimal, formatNumber, formatPercent, formatPercentRaw } from '@/lib/format';
import { cn } from '@/lib/utils';

interface Demand {
  clicks_before?: number;
  clicks_after?: number;
  delta_percent?: number;
  days_declining?: number;
  query_cluster?: string;
  competing_pages?: number;
  total_clicks?: number;
  volatility?: number;
  cluster_name?: string;
  cluster_demand?: number;
  coverage_percentage?: number;
  missing_entity?: string;
  // Keyword opportunity fields
  query?: string;
  position?: number;
  impressions?: number;
  clicks?: number;
  ctr?: number;
  expected_ctr?: number;
  ctr_gap_percent?: number;
  metadata?: Record<string, unknown>;
}

interface RelatedOpportunity {
  type: 'recommendation' | 'freshness' | 'cannibalization' | 'topic_gap' | 'keyword_opportunity';
  id: number;
  relationship: string;
}

interface Opportunity {
  opportunity_type:
    | 'recommendation'
    | 'freshness'
    | 'cannibalization'
    | 'topic_gap'
    | 'keyword_opportunity';
  opportunity_id: number;
  page_url: string;
  demand: Demand | null;
  issue: string;
  action: string;
  confidence: number;
  impact_score: number;
  reasoning: string;
  evidence?: Record<string, unknown>;
  status?: string;
  lifecycle_status?: string;
  related_opportunities?: RelatedOpportunity[];
  keyword_opportunity_type?: 'striking_distance' | 'ctr_gap' | 'rising_query' | 'content_gap';
}

interface UnifiedCardProps {
  opportunity: Opportunity;
  siteId: number;
  selected?: boolean;
  onToggleSelection?: () => void;
}

const OPPORTUNITY_TYPE_CONFIG: Record<
  string,
  { label: string; variant: 'default' | 'medium' | 'secondary' | 'outline' }
> = {
  recommendation: { label: 'Recommendation', variant: 'default' },
  freshness: { label: 'Freshness', variant: 'medium' },
  cannibalization: { label: 'Cannibalization', variant: 'secondary' },
  topic_gap: { label: 'Topic Gap', variant: 'outline' },
  keyword_opportunity: { label: 'Keyword Opportunity', variant: 'default' },
};

const RELATIONSHIP_LABELS: Record<string, string> = {
  internal_linking_for_same_cluster: 'Internal linking for cluster',
  cannibalization_overlap: 'Related cannibalization',
  internal_linking_for_primary_page: 'Internal linking support',
  addresses_topic_gap: 'Addresses topic gap',
};

const OpportunityTypeBadge = memo(({ type }: { type: string }) => {
  const config = OPPORTUNITY_TYPE_CONFIG[type] ?? {
    label: type.replace(/_/g, ' '),
    variant: 'default' as const,
  };
  return <Badge variant={config.variant}>{config.label}</Badge>;
});
OpportunityTypeBadge.displayName = 'OpportunityTypeBadge';

function renderDemand(demand: Demand | null): React.ReactNode {
  if (!demand) {
    return <span className="text-sm text-muted-foreground">No demand data</span>;
  }

  // Recommendation / Freshness: clicks before/after
  if (demand.clicks_before !== undefined && demand.clicks_after !== undefined) {
    return (
      <div className="space-y-1">
        <div className="flex items-center justify-between">
          <span className="text-sm text-muted-foreground">Clicks</span>
          {demand.delta_percent !== undefined && (
            <MetricDelta value={demand.delta_percent} format="percent" />
          )}
        </div>
        <div className="flex items-center gap-2 text-sm">
          <span className="tabular-nums">{formatNumber(demand.clicks_before)}</span>
          <span className="text-muted-foreground">&rarr;</span>
          <span className="tabular-nums">{formatNumber(demand.clicks_after)}</span>
        </div>
        {demand.days_declining !== undefined && (
          <p className="text-xs text-muted-foreground">
            Declining for {demand.days_declining} days
          </p>
        )}
      </div>
    );
  }

  // Cannibalization: competing pages
  if (demand.query_cluster !== undefined && demand.competing_pages !== undefined) {
    return (
      <div className="space-y-1">
        <p className="text-sm font-medium">{demand.query_cluster}</p>
        <p className="text-sm text-muted-foreground">{demand.competing_pages} competing pages</p>
        {demand.total_clicks !== undefined && (
          <p className="text-sm">
            <span className="text-muted-foreground">Total clicks:</span>{' '}
            <span className="tabular-nums">{formatNumber(demand.total_clicks)}</span>
          </p>
        )}
        {demand.volatility !== undefined && (
          <p className="text-sm">
            <span className="text-muted-foreground">Volatility:</span>{' '}
            <span className="tabular-nums">{formatDecimal(demand.volatility)}</span>
          </p>
        )}
      </div>
    );
  }

  // Topic Gap: cluster data
  if (demand.cluster_name !== undefined) {
    return (
      <div className="space-y-1">
        <p className="text-sm font-medium">{demand.cluster_name}</p>
        {demand.cluster_demand !== undefined && (
          <p className="text-sm">
            <span className="text-muted-foreground">Cluster demand:</span>{' '}
            <span className="tabular-nums">{formatNumber(demand.cluster_demand)}</span>
          </p>
        )}
        {demand.coverage_percentage !== undefined && (
          <p className="text-sm">
            <span className="text-muted-foreground">Coverage:</span>{' '}
            <span className="tabular-nums">{formatPercentRaw(demand.coverage_percentage)}</span>
          </p>
        )}
        {demand.missing_entity !== undefined && (
          <p className="text-sm">
            <span className="text-muted-foreground">Missing:</span> {demand.missing_entity}
          </p>
        )}
      </div>
    );
  }

  // Keyword Opportunity: query data
  if (demand.query !== undefined) {
    return (
      <div className="space-y-1">
        <p className="text-sm font-medium">{demand.query}</p>
        {demand.position !== undefined && (
          <p className="text-sm">
            <span className="text-muted-foreground">Position:</span>{' '}
            <span className="tabular-nums">{formatDecimal(demand.position, 1)}</span>
          </p>
        )}
        {demand.impressions !== undefined && (
          <p className="text-sm">
            <span className="text-muted-foreground">Impressions:</span>{' '}
            <span className="tabular-nums">{formatNumber(demand.impressions)}</span>
          </p>
        )}
        {demand.clicks !== undefined && (
          <p className="text-sm">
            <span className="text-muted-foreground">Clicks:</span>{' '}
            <span className="tabular-nums">{formatNumber(demand.clicks)}</span>
          </p>
        )}
        {demand.ctr !== undefined && (
          <p className="text-sm">
            <span className="text-muted-foreground">CTR:</span>{' '}
            <span className="tabular-nums">{formatPercent(demand.ctr, 2)}</span>
          </p>
        )}
      </div>
    );
  }

  return <span className="text-sm text-muted-foreground">No demand data</span>;
}

/**
 * Get the detail page route for a given opportunity type
 */
function getOpportunityRoute(siteId: number, type: string, id: number): string {
  const routeMap: Record<string, { name: string; param: string }> = {
    recommendation: { name: 'recommendations.show', param: 'recommendation' },
    freshness: { name: 'freshness.show', param: 'freshnessRecommendation' },
    cannibalization: { name: 'cannibalization.show', param: 'cannibalizationCase' },
    topic_gap: { name: 'topic-clusters.show', param: 'cluster' },
    keyword_opportunity: { name: 'opportunity-map.index', param: '' },
  };

  const config = routeMap[type];
  if (!config) {
    return '#';
  }

  // Special case for keyword_opportunity since it doesn't have a detail page yet
  if (type === 'keyword_opportunity') {
    return route(config.name, { site: siteId });
  }

  return route(config.name, { site: siteId, [config.param]: id });
}

/**
 * Check if opportunity type can have a brief generated.
 * Only topic_gap and content_gap keyword opportunities are natural
 * handoff points for new content creation.
 */
function canGenerateBrief(opportunity: Opportunity): boolean {
  if (opportunity.opportunity_type === 'topic_gap') return true;
  if (
    opportunity.opportunity_type === 'keyword_opportunity' &&
    opportunity.keyword_opportunity_type === 'content_gap'
  )
    return true;
  return false;
}

/**
 * Get parameters for generating a content brief
 */
function getBriefParams(opportunity: Opportunity): Record<string, unknown> {
  const params: Record<string, unknown> = {};

  if (opportunity.opportunity_type === 'keyword_opportunity' && opportunity.demand?.query) {
    params.keyword = opportunity.demand.query;
  }

  if (opportunity.opportunity_type === 'topic_gap' && opportunity.demand?.cluster_name) {
    params.cluster = opportunity.demand.cluster_name;
  }

  return params;
}

function UnifiedCard({
  opportunity,
  siteId,
  selected = false,
  onToggleSelection,
}: UnifiedCardProps) {
  const [detailsOpen, setDetailsOpen] = useState(false);

  const toggleDetails = useCallback(() => {
    setDetailsOpen((prev) => !prev);
  }, []);

  return (
    <div className="rounded-lg border bg-card p-4">
      {/* Header Section */}
      <div className="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between sm:gap-4">
        <div className="flex items-start gap-3 min-w-0">
          {onToggleSelection && (
            <input
              type="checkbox"
              checked={selected}
              onChange={onToggleSelection}
              className="mt-1 h-4 w-4 cursor-pointer rounded border-input text-primary focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
              aria-label={`Select opportunity: ${opportunity.issue}`}
            />
          )}
          <div className="flex flex-col gap-2 min-w-0">
            <OpportunityTypeBadge type={opportunity.opportunity_type} />
            <p className="text-xs text-muted-foreground truncate" title={opportunity.page_url}>
              {opportunity.page_url}
            </p>
          </div>
        </div>
        <div className="flex items-center gap-4 sm:shrink-0">
          <div className="text-center">
            <p className="text-2xl font-bold">{Math.round(opportunity.impact_score)}</p>
            <p className="text-xs text-muted-foreground">Impact</p>
          </div>
          <div className="text-center">
            <p className="text-2xl font-bold">{Math.round(opportunity.confidence)}</p>
            <p className="text-xs text-muted-foreground">Confidence</p>
          </div>
        </div>
      </div>

      {/* Demand / Issue / Action Section */}
      <div className="mt-4 grid gap-4 sm:grid-cols-3">
        {/* Demand */}
        <div>
          <h4 className="text-xs font-semibold uppercase tracking-wide text-muted-foreground mb-2">
            Demand
          </h4>
          {renderDemand(opportunity.demand)}
        </div>

        {/* Issue */}
        <div>
          <h4 className="text-xs font-semibold uppercase tracking-wide text-muted-foreground mb-2">
            Issue
          </h4>
          <p className="text-sm">{opportunity.issue}</p>
        </div>

        {/* Action */}
        <div>
          <h4 className="text-xs font-semibold uppercase tracking-wide text-muted-foreground mb-2">
            Action
          </h4>
          <p className="text-sm capitalize">{opportunity.action.replace(/_/g, ' ')}</p>
        </div>
      </div>

      {/* Action Buttons */}
      <div className="mt-3 flex flex-wrap items-center gap-2">
        <button
          type="button"
          aria-expanded={detailsOpen}
          onClick={toggleDetails}
          className="text-sm text-muted-foreground cursor-pointer hover:text-foreground flex items-center gap-1 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 rounded-sm"
        >
          <ChevronRight
            className={cn('h-3 w-3 transition-transform duration-200', detailsOpen && 'rotate-90')}
          />
          View details
        </button>
        {canGenerateBrief(opportunity) && (
          <Link
            href={(() => {
              const params = new URLSearchParams(
                getBriefParams(opportunity) as Record<string, string>,
              );
              return (
                route('content-briefs.index', { site: siteId }) +
                (params.toString() ? '?' + params.toString() : '')
              );
            })()}
            className="inline-flex items-center gap-1.5 rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground hover:bg-primary/90 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
          >
            <BookOpen className="h-3.5 w-3.5" />
            Create Brief
          </Link>
        )}
      </div>

      {/* Details Section (Progressive Disclosure) */}
      <div
        className={cn(
          'grid transition-all duration-200 ease-in-out',
          detailsOpen ? 'grid-rows-[1fr] opacity-100 mt-2' : 'grid-rows-[0fr] opacity-0',
        )}
      >
        <div className="overflow-hidden">
          <div className="space-y-3 text-sm">
            <div>
              <h5 className="font-medium mb-1">Reasoning</h5>
              <p className="text-muted-foreground">{opportunity.reasoning}</p>
            </div>
            {opportunity.evidence && Object.keys(opportunity.evidence).length > 0 && (
              <div>
                <h5 className="font-medium mb-1">Evidence</h5>
                <pre className="text-xs bg-muted p-2 rounded overflow-x-auto">
                  {JSON.stringify(opportunity.evidence, null, 2)}
                </pre>
              </div>
            )}
            {opportunity.related_opportunities && opportunity.related_opportunities.length > 0 && (
              <div>
                <h5 className="font-medium mb-2">Related Opportunities</h5>
                <div className="flex flex-wrap gap-2">
                  {opportunity.related_opportunities.map((related, index) => {
                    const typeConfig = OPPORTUNITY_TYPE_CONFIG[related.type] ?? {
                      label: related.type.replace(/_/g, ' '),
                      variant: 'default' as const,
                    };
                    const relationshipLabel =
                      RELATIONSHIP_LABELS[related.relationship] ??
                      related.relationship.replace(/_/g, ' ');

                    return (
                      <Link
                        key={`${related.type}-${related.id}-${index}`}
                        href={getOpportunityRoute(siteId, related.type, related.id)}
                        className="inline-flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-md border border-input bg-background hover:bg-accent hover:text-accent-foreground transition-colors"
                        title={relationshipLabel}
                      >
                        <span>{typeConfig.label}</span>
                        <ArrowRight className="h-3 w-3" />
                      </Link>
                    );
                  })}
                </div>
              </div>
            )}
            {opportunity.status && (
              <div>
                <span className="font-medium">Status: </span>
                <span className="text-muted-foreground capitalize">
                  {opportunity.status.replace(/_/g, ' ')}
                </span>
              </div>
            )}
          </div>
        </div>
      </div>
    </div>
  );
}

export default memo(UnifiedCard);
