import React, { useState, useCallback, useRef, memo } from 'react';
import { useAuth } from '../../../auth/AuthProvider';
import { searchGeoTargets, getDemographics } from '../../../services/wizardApi';
import HelpIcon from '../../../components/HelpIcon';

// ── Static Options ──

const AGE_RANGES = [
  { id: 'AGE_18_24', label: '18–24' },
  { id: 'AGE_25_34', label: '25–34' },
  { id: 'AGE_35_44', label: '35–44' },
  { id: 'AGE_45_54', label: '45–54' },
  { id: 'AGE_55_64', label: '55–64' },
  { id: 'AGE_65_UP', label: '65+' },
];

const GENDERS = [
  { id: 'MALE', label: 'Male' },
  { id: 'FEMALE', label: 'Female' },
  { id: 'UNDETERMINED', label: 'All Genders' },
];

const INCOMES = [
  { id: 'TOP_10',    label: 'Top 10%' },
  { id: 'TOP_11_20', label: '11–20%' },
  { id: 'TOP_21_30', label: '21–30%' },
  { id: 'TOP_31_40', label: '31–40%' },
  { id: 'TOP_41_50', label: '41–50%' },
  { id: 'LOWER_50',  label: 'Lower 50%' },
];

// ── Factor Derivation ──

export function deriveAgeSkew(selectedAges) {
  if (!selectedAges || selectedAges.length === 0) return null;

  const youngSet = ['AGE_18_24', 'AGE_25_34'];
  const matureSet = ['AGE_45_54', 'AGE_55_64', 'AGE_65_UP'];

  const youngCount = selectedAges.filter(a => youngSet.includes(a)).length;
  const matureCount = selectedAges.filter(a => matureSet.includes(a)).length;

  if (youngCount > 0 && matureCount === 0) return 'young';
  if (matureCount > 0 && youngCount === 0) return 'mature';
  if (youngCount > matureCount) return 'young';
  if (matureCount > youngCount) return 'mature';
  return null;
}

export function deriveMarketScope(locations) {
  if (!locations || locations.length === 0) return 'national';

  const types = locations.map(l => (l.type || '').toLowerCase());
  if (types.some(t => t === 'country')) return 'national';

  const states = new Set();
  locations.forEach(loc => {
    const parts = (loc.canonicalName || '').split(',').map(s => s.trim());
    if (parts.length >= 2) states.add(parts[parts.length - 2]);
  });

  const stateTypes = types.filter(t => ['state', 'province', 'region'].includes(t));
  if (stateTypes.length >= 2) return 'national';
  if (stateTypes.length === 1) return 'regional';

  if (states.size <= 1) return 'local';
  if (states.size <= 3) return 'regional';
  return 'national';
}

// ── Chip Select Component ──

function ChipSelect({ options, selected, onToggle, censusHighlighted }) {
  return (
    <div className="chip-row">
      {options.map(opt => {
        const isSelected = selected.includes(opt.id);
        const isCensus = censusHighlighted?.includes(opt.id);
        return (
          <button
            key={opt.id}
            type="button"
            className={`chip ${isSelected ? 'active' : ''} ${isCensus && !isSelected ? 'census-suggested' : ''}`}
            onClick={() => onToggle(opt.id)}
            title={isCensus ? 'Recommended based on local demographics' : ''}
          >
            {opt.label}
          </button>
        );
      })}
    </div>
  );
}

// ── Market Insight Bar ──

function MarketInsightBar({ insights, census, loading }) {
  if (loading) {
    return (
      <div className="market-insight-bar loading">
        <span className="btn-spinner" style={{ width: 14, height: 14 }} />
        <span>Loading market data…</span>
      </div>
    );
  }

  if (!insights || insights.length === 0) return null;

  return (
    <div className="market-insight-bar">
      <div className="insight-header">
        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
          <path d="M3 3v18h18" />
          <path d="M18.7 8l-5.1 5.2-2.8-2.7L7 14.3" />
        </svg>
        <span className="insight-title">Market Profile</span>
        <span className="insight-source">U.S. Census ACS</span>
      </div>
      <div className="insight-chips">
        {insights.map((insight, i) => (
          <span key={i} className="insight-chip">{insight}</span>
        ))}
      </div>
      {census && (
        <div className="insight-details">
          <div className="insight-grid">
            {census.medianIncome > 0 && (
              <div className="insight-metric">
                <span className="metric-value">${(census.medianIncome / 1000).toFixed(0)}K</span>
                <span className="metric-label">Median Income</span>
              </div>
            )}
            {census.medianHomeValue > 0 && (
              <div className="insight-metric">
                <span className="metric-value">${(census.medianHomeValue / 1000).toFixed(0)}K</span>
                <span className="metric-label">Home Value</span>
              </div>
            )}
            {census.pctBachelorPlus > 0 && (
              <div className="insight-metric">
                <span className="metric-value">{census.pctBachelorPlus}%</span>
                <span className="metric-label">College Educated</span>
              </div>
            )}
            {census.pctOwnerOccupied > 0 && (
              <div className="insight-metric">
                <span className="metric-value">{census.pctOwnerOccupied}%</span>
                <span className="metric-label">Homeowners</span>
              </div>
            )}
          </div>
        </div>
      )}
    </div>
  );
}

// ── Audience Step ──

const AudienceStep = memo(function AudienceStep({ data, onChange }) {
  const { sessionToken } = useAuth();

  const [geoQuery, setGeoQuery] = useState('');
  const [geoResults, setGeoResults] = useState([]);
  const [geoSearching, setGeoSearching] = useState(false);
  const [censusLoading, setCensusLoading] = useState(false);
  const searchTimeout = useRef(null);

  // Migrate old saved data: clear legacy Male/Female defaults
  // so census can set All Genders on first ZIP lookup
  const migrateData = (d) => {
    if (!d || !d.demographics) return d;
    const g = d.demographics.genders;
    // If saved data has exactly ['MALE','FEMALE'] and no census data,
    // it's the old hardcoded default — clear it
    if (g && g.length === 2
        && g.includes('MALE') && g.includes('FEMALE')
        && !d.censusData) {
      return { ...d, demographics: { ...d.demographics, genders: [] } };
    }
    return d;
  };

  const migrated = migrateData(data);

  const state = {
    locations: [],
    demographics: {
      ageRanges: [],
      genders: [],
      incomes: [],
    },
    ageSkew: null,
    marketScope: 'national',
    censusData: null,
    censusInsights: null,
    censusRecommendations: null,
    ...migrated,
  };

  const update = useCallback((patch) => {
    const next = { ...state, ...patch };
    next.ageSkew = deriveAgeSkew(next.demographics.ageRanges);
    next.marketScope = deriveMarketScope(next.locations);
    onChange(next);
  }, [state, onChange]);

  const updateDemo = (key, value) => {
    update({ demographics: { ...state.demographics, [key]: value } });
  };

  const toggleDemo = (key, id) => {
    const current = state.demographics[key] || [];
    const next = current.includes(id)
      ? current.filter(x => x !== id)
      : [...current, id];
    updateDemo(key, next);
  };

  // ── Census Lookup ──
  // Accepts currentLocations to avoid stale closure overwriting location state

  const fetchCensusData = async (zcta, currentLocations) => {
    if (!zcta || zcta.length !== 5 || !sessionToken) return;

    setCensusLoading(true);
    try {
      const res = await getDemographics(zcta, sessionToken);
      if (res.ok && res.data) {
        const d = res.data;
        const recs = d.recommendations || {};

        // Always apply census recommendations for new ZIP data
        const newAges = recs.ageRanges || state.demographics.ageRanges;
        const newIncomes = recs.incomes || state.demographics.incomes;
        const newGenders = state.demographics.genders.length === 0
          ? ['UNDETERMINED'] : state.demographics.genders;

        update({
          // Preserve the locations that were set before this async call
          locations: currentLocations || state.locations,
          demographics: {
            ...state.demographics,
            ageRanges: newAges,
            incomes: newIncomes,
            genders: newGenders,
          },
          censusData: d.census || null,
          censusInsights: d.insights || null,
          censusRecommendations: recs,
        });
      }
    } catch (e) {
      console.warn('Census lookup error:', e);
    }
    setCensusLoading(false);
  };

  // ── Direct ZIP Lookup ──

  const isZipInput = /^\d{5}$/.test(geoQuery.trim());

  const addZipDirect = () => {
    const zip = geoQuery.trim();
    if (!/^\d{5}$/.test(zip)) return;
    if (state.locations.some(l => l.name === zip)) return;

    const newLocations = [...state.locations, {
      id: `zip_${zip}`,
      name: zip,
      type: 'Zip Code',
      canonicalName: `${zip}, United States`,
    }];

    update({ locations: newLocations });
    setGeoQuery('');
    setGeoResults([]);
    fetchCensusData(zip, newLocations);
  };

  const onGeoKeyDown = (e) => {
    if (e.key === 'Enter' && isZipInput) {
      e.preventDefault();
      addZipDirect();
    }
  };

  // ── Geo Search ──

  const handleGeoSearch = async (query) => {
    if (!query || query.length < 2) { setGeoResults([]); return; }
    setGeoSearching(true);
    try {
      const res = await searchGeoTargets(query, sessionToken);
      if (res.ok) {
        const results = res.data?.result?.data?.results
          || res.data?.data?.results
          || res.data?.results || [];
        setGeoResults(results);
      }
    } catch (e) {
      console.warn('Geo search error:', e);
    }
    setGeoSearching(false);
  };

  const onGeoInput = (val) => {
    setGeoQuery(val);
    clearTimeout(searchTimeout.current);
    // Only fire geo search for non-ZIP queries
    if (!/^\d{3,5}$/.test(val.trim())) {
      searchTimeout.current = setTimeout(() => handleGeoSearch(val), 400);
    } else {
      setGeoResults([]);
    }
  };

  const addLocation = (geo) => {
    if (state.locations.some(l => l.id === geo.id)) return;

    const newLocations = [...state.locations, {
      id: geo.id,
      name: geo.name,
      type: geo.targetType || geo.type || 'Location',
      canonicalName: geo.canonicalName,
    }];

    update({ locations: newLocations });
    setGeoQuery('');
    setGeoResults([]);

    const zcta = extractZcta(geo);
    if (zcta) fetchCensusData(zcta, newLocations);
  };

  const removeLocation = (id) => {
    const remaining = state.locations.filter(l => l.id !== id);
    const patch = { locations: remaining };

    if (!remaining.some(l => extractZcta(l))) {
      patch.censusData = null;
      patch.censusInsights = null;
      patch.censusRecommendations = null;
      patch.demographics = {
        ...state.demographics,
        ageRanges: [],
        genders: [],
        incomes: [],
      };
    }

    update(patch);
  };

  const factorLabels = {
    ageSkew: { young: 'Younger audience', mature: 'Mature audience', null: 'Balanced' },
    marketScope: { local: 'Local market', regional: 'Regional', national: 'National' },
  };

  return (
    <div className="wizard-step-content">
      <div className="step-intro">
        <div className="step-intro-header">
          <h2>Who is your audience?</h2>
          <HelpIcon helpKey="client.wizard.audience" label="About this step" />
        </div>
        <p>Add your target location and we'll analyze the local market to recommend the best audience targeting for your campaign.</p>
      </div>

      {/* ── Location Targeting ── */}
      <div className="audience-section">
        <h3>
          <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
            <path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0118 0z" />
            <circle cx="12" cy="10" r="3" />
          </svg>
          Target Locations
        </h3>
        <div className="geo-search-wrap">
          <div className="geo-input-row">
            <input
              className="form-input"
              placeholder="Enter a ZIP code or search cities, states…"
              value={geoQuery}
              onChange={e => onGeoInput(e.target.value)}
              onKeyDown={onGeoKeyDown}
            />
            {isZipInput && (
              <button
                type="button"
                className="btn btn-primary btn-sm zip-lookup-btn"
                onClick={addZipDirect}
              >
                Look Up
              </button>
            )}
          </div>
          {geoSearching && <span className="geo-search-spinner"><span className="btn-spinner" /></span>}
          {geoResults.length > 0 && (
            <div className="geo-dropdown">
              {geoResults.map(geo => (
                <button
                  key={geo.id}
                  type="button"
                  className="geo-result"
                  onClick={() => addLocation(geo)}
                  disabled={state.locations.some(l => l.id === geo.id)}
                >
                  <span className="geo-result-name">{geo.name}</span>
                  <span className="geo-result-type">{geo.targetType || geo.type}</span>
                  <span className="geo-result-canonical">{geo.canonicalName}</span>
                </button>
              ))}
            </div>
          )}
        </div>

        {state.locations.length > 0 && (
          <div className="location-chips">
            {state.locations.map(loc => (
              <span key={loc.id} className="location-chip">
                <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
                  <path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0118 0z" />
                  <circle cx="12" cy="10" r="3" />
                </svg>
                {loc.name}
                <button type="button" onClick={() => removeLocation(loc.id)} className="chip-remove">×</button>
              </span>
            ))}
          </div>
        )}

        {state.locations.length === 0 && (
          <div className="field-hint" style={{ marginTop: 8 }}>
            Enter a ZIP code to see local market demographics and auto-fill targeting recommendations.
          </div>
        )}
      </div>

      {/* ── Market Insight Bar (census-powered) ── */}
      <MarketInsightBar
        insights={state.censusInsights}
        census={state.censusData}
        loading={censusLoading}
      />

      {/* ── Demographics ── */}
      <div className="audience-section">
        <h3>
          <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
            <path d="M17 21v-2a4 4 0 00-4-4H5a4 4 0 00-4 4v2" />
            <circle cx="9" cy="7" r="4" />
            <path d="M23 21v-2a4 4 0 00-3-3.87" />
            <path d="M16 3.13a4 4 0 010 7.75" />
          </svg>
          Demographics
          {state.censusData && (
            <span className="census-badge">Auto-populated from market data</span>
          )}
        </h3>

        <div className="demo-group">
          <label>Age Ranges</label>
          <ChipSelect
            options={AGE_RANGES}
            selected={state.demographics.ageRanges}
            onToggle={(id) => toggleDemo('ageRanges', id)}
            censusHighlighted={state.censusRecommendations?.ageRanges}
          />
          {state.demographics.ageRanges.length === 0 && !state.censusData && (
            <span className="field-hint">Add a ZIP code above to auto-fill, or select manually</span>
          )}
        </div>

        <div className="demo-group">
          <label>Gender</label>
          <ChipSelect
            options={GENDERS}
            selected={state.demographics.genders}
            onToggle={(id) => toggleDemo('genders', id)}
          />
          {state.demographics.genders.length === 0 && (
            <span className="field-hint">Will default to All Genders when market data loads</span>
          )}
        </div>

        <div className="demo-group">
          <label>Household Income
            {state.censusData
              ? <span className="census-badge small">Market-informed</span>
              : <span className="optional-tag">Optional</span>
            }
          </label>
          <ChipSelect
            options={INCOMES}
            selected={state.demographics.incomes}
            onToggle={(id) => toggleDemo('incomes', id)}
            censusHighlighted={state.censusRecommendations?.incomes}
          />
        </div>
      </div>

      {/* ── Audience Profile Summary ── */}
      <div className="audience-profile-summary">
        <div className="audience-profile-header">
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
            <path d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z" />
          </svg>
          <span className="audience-profile-title">
            {state.censusData ? 'Market-Informed Profile' : 'Audience Profile'}
          </span>
          <span className="audience-profile-hint">
            {state.censusData
              ? 'Based on U.S. Census data for your target area — adjust above to override'
              : 'Derived from your selections — used for channel recommendations'}
          </span>
        </div>
        <div className="profile-factors">
          <div className="profile-factor">
            <span className="factor-label">Age Profile</span>
            <span className={`factor-value ${state.ageSkew ? 'has-value' : 'neutral'}`}>
              {factorLabels.ageSkew[state.ageSkew] || 'Balanced'}
            </span>
          </div>
          <div className="profile-factor">
            <span className="factor-label">Market Scope</span>
            <span className={`factor-value has-value`}>
              {factorLabels.marketScope[state.marketScope] || 'National'}
            </span>
          </div>
        </div>
      </div>
    </div>
  );
});

// ── Helpers ──

function extractZcta(geo) {
  const geoType = (geo.type || geo.targetType || '').toLowerCase();
  if (geoType === 'zip code' || geoType === 'postal code') {
    const match = (geo.name || '').match(/\b(\d{5})\b/);
    return match ? match[1] : null;
  }
  const nameMatch = (geo.name || '').match(/^\d{5}$/);
  if (nameMatch) return nameMatch[0];
  const canonMatch = (geo.canonicalName || '').match(/\b(\d{5})\b/);
  if (canonMatch) return canonMatch[1];
  return null;
}

export default AudienceStep;
