/**
 * Survey Routes
 *
 * Weekly survey system with credit rewards.
 */

import { Router, Request, Response } from 'express';
import { authMiddleware, optionalAuth } from '../middleware/auth';
import pool from '../db';
import { recordLedgerEntry } from '../models/ledger';
import { getPickBalance, SURVEY_BONUS_FORECASTS } from '../models/user';
import { isUuid } from '../lib/uuid';

const router = Router();

function normalizeSurveyQuestions(rawQuestions: unknown): unknown[] {
  if (Array.isArray(rawQuestions)) return rawQuestions;
  if (typeof rawQuestions !== 'string' || rawQuestions.trim().length === 0) return [];

  try {
    const parsed = JSON.parse(rawQuestions);
    return Array.isArray(parsed) ? parsed : [];
  } catch {
    return [];
  }
}

function resolveSurveyReward(rawReward: unknown): number {
  const parsed = Number(rawReward);
  return Number.isFinite(parsed) && parsed > 0
    ? Math.max(parsed, SURVEY_BONUS_FORECASTS)
    : SURVEY_BONUS_FORECASTS;
}

// GET /api/survey/current — active survey for this week (null if completed/throttled)
router.get('/current', optionalAuth, async (req: Request, res: Response) => {
  try {
    // Find the correct survey for this week (auto-rotate by week_start date)
    const { rows: surveys } = await pool.query(
      `SELECT * FROM rm_surveys
       WHERE is_active = TRUE
         AND week_start <= CURRENT_DATE
       ORDER BY week_start DESC LIMIT 1`
    );

    if (surveys.length === 0) {
      res.json({ survey: null });
      return;
    }

    const survey = surveys[0];

    // If authenticated, apply user-specific checks
    let hasCompletedAnySurvey = false;
    if (req.user) {
      const userId = req.user.userId;

      // Check if user already completed THIS survey
      const { rows: responses } = await pool.query(
        `SELECT id FROM rm_survey_responses WHERE survey_id = $1 AND user_id = $2`,
        [survey.id, userId]
      );

      // Check if user has completed ANY survey (for free trial gating)
      const { rows: anySurvey } = await pool.query(
        `SELECT 1 FROM rm_survey_responses WHERE user_id = $1 LIMIT 1`,
        [userId]
      );
      hasCompletedAnySurvey = anySurvey.length > 0;

      // Check if user submitted any survey in last 7 days (weekly cooldown)
      const { rows: recentSubmit } = await pool.query(
        `SELECT id FROM rm_survey_responses WHERE user_id = $1 AND created_at > NOW() - INTERVAL '7 days' LIMIT 1`,
        [userId]
      );
      const onCooldown = recentSubmit.length > 0;

      if (responses.length > 0) {
        // Completed this specific survey — check if on weekly cooldown
        if (onCooldown) {
          res.json({ survey: null, completed: true, hasCompletedAnySurvey, nextSurveyAvailable: 'next_week' });
          return;
        }
        res.json({ survey: null, completed: true, hasCompletedAnySurvey });
        return;
      }

      // On weekly cooldown from a different survey
      if (onCooldown) {
        res.json({ survey: null, onCooldown: true, hasCompletedAnySurvey, nextSurveyAvailable: 'next_week' });
        return;
      }

      // Paid user throttle: weathermen + purchasers see surveys every ~5 weeks
      const { rows: userRows } = await pool.query(
        `SELECT is_weatherman, preferences FROM rm_users WHERE id = $1`,
        [userId]
      );
      if (userRows.length > 0) {
        const user = userRows[0];
        const hasPurchases = await pool.query(
          `SELECT 1 FROM rm_purchases WHERE user_id = $1 LIMIT 1`, [userId]
        );
        const isPaid = user.is_weatherman || (hasPurchases.rows.length > 0);
        if (isPaid) {
          const prefs = user.preferences || {};
          const lastSurvey = prefs.last_survey_at ? new Date(prefs.last_survey_at) : null;
          if (lastSurvey) {
            const daysSince = (Date.now() - lastSurvey.getTime()) / (1000 * 60 * 60 * 24);
            if (daysSince < 35) {
              res.json({ survey: null, hasCompletedAnySurvey });
              return;
            }
          }
        }
      }
    }

    res.json({
      survey: {
        id: survey.id,
        title: survey.title,
        questions: normalizeSurveyQuestions(survey.questions),
        creditReward: resolveSurveyReward(survey.credit_reward),
      },
      hasCompletedAnySurvey,
    });
  } catch (err) {
    console.error('Survey current error:', err);
    res.status(500).json({ error: 'Failed to fetch survey' });
  }
});

/** Extract user profile tags from survey answers — handles all weekly surveys */
function buildProfileTags(answers: Record<string, string>): Record<string, any> {
  const profile: Record<string, any> = {};

  // ── Week 1: Help Us Improve Rainmaker ──────────────────────

  // League preferences
  const league = answers.leagues?.toLowerCase() || '';
  if (league === 'multiple') {
    profile.preferred_leagues = ['nba', 'nfl', 'nhl', 'mlb'];
  } else if (league) {
    profile.preferred_leagues = [league === 'soccer' ? 'epl' : league];
  }

  // Bet type preferences
  const betType = answers.bet_type?.toLowerCase() || '';
  if (betType) {
    profile.prefers_props = betType.includes('prop');
    profile.prefers_spreads = betType.includes('spread');
    profile.prefers_parlays = betType.includes('parlay');
    profile.bet_style = betType.includes('mix') ? 'mixed' : betType.split(' ')[0] || 'mixed';
  }

  // Risk tolerance
  const risk = answers.risk?.toLowerCase() || '';
  if (risk) {
    if (risk.includes('conservative')) profile.risk_tolerance = 'low';
    else if (risk.includes('aggressive')) profile.risk_tolerance = 'high';
    else profile.risk_tolerance = 'medium';
  }

  // Bankroll band
  const bankroll = answers.bankroll || '';
  if (bankroll) {
    if (bankroll.includes('Under') || bankroll.includes('$50-')) profile.bankroll_band = 'low';
    else if (bankroll.includes('$200-') || bankroll.includes('$500-')) profile.bankroll_band = 'mid';
    else if (bankroll.includes('$1000')) profile.bankroll_band = 'high';
    else profile.bankroll_band = 'low';
  }

  // Sportsbook
  const book = answers.sportsbook || '';
  if (book) profile.sportsbook = book.toLowerCase().replace(/\s+/g, '');

  // ── Week 2: Your Betting Routine ───────────────────────────

  if (answers.bet_timing) profile.bet_timing = answers.bet_timing.toLowerCase();
  if (answers.bets_per_week) profile.bets_per_week = answers.bets_per_week;
  if (answers.line_movements) {
    const lm = answers.line_movements.toLowerCase();
    profile.checks_lines = lm === 'always' || lm === 'sometimes';
    profile.line_awareness = lm.includes('what') ? 'none' : lm;
  }
  if (answers.info_source) profile.info_source = answers.info_source.toLowerCase();
  if (answers.pay_for_alerts) {
    profile.wants_line_alerts = answers.pay_for_alerts.toLowerCase() === 'absolutely';
    profile.line_alert_interest = answers.pay_for_alerts.toLowerCase();
  }

  // ── Week 3: What Would You Pay For? ────────────────────────

  if (answers.most_valuable) profile.most_valuable_feature = answers.most_valuable.toLowerCase();
  if (answers.weekly_pass) {
    const wp = answers.weekly_pass.toLowerCase();
    profile.weekly_pass_interest = wp.includes('yes');
    profile.weekly_pass_price_point = wp.includes('$20') ? 20 : wp.includes('$10') ? 10 : 0;
  }
  if (answers.props_importance) {
    const pi = answers.props_importance.toLowerCase();
    profile.props_importance = pi.includes('essential') ? 'high' : pi.includes('nice') ? 'medium' : 'low';
  }
  if (answers.referral_interest) {
    profile.referral_likely = answers.referral_interest.toLowerCase() === 'definitely';
  }
  if (answers.missing_feature) profile.missing_feature = answers.missing_feature.toLowerCase();

  // ── Week 4: Your Results ───────────────────────────────────

  if (answers.profited) {
    const p = answers.profited.toLowerCase();
    profile.profited = p.includes('yes');
    profile.profit_level = p.includes('significantly') ? 'high' : p.includes('slightly') ? 'low' : p.includes('even') ? 'even' : 'negative';
  }
  if (answers.forecasts_acted) profile.forecasts_acted = answers.forecasts_acted;
  if (answers.bet_confidence) profile.confidence_driver = answers.bet_confidence.toLowerCase();
  if (answers.subscription) {
    const sub = answers.subscription.toLowerCase();
    profile.subscription_interest = !sub.includes('no');
    profile.subscription_price_point = sub.includes('$30') ? 30 : sub.includes('$15') ? 15 : 0;
  }
  if (answers.rating) {
    const r = answers.rating.match(/^(\d)/);
    profile.nps_rating = r ? parseInt(r[1]) : null;
  }

  // ── Week 5: Social & Community ─────────────────────────────

  if (answers.follows_twitter) {
    profile.follows_twitter = answers.follows_twitter.toLowerCase() === 'yes';
    profile.twitter_convertible = answers.follows_twitter.toLowerCase().includes('will');
  }
  if (answers.discord_interest) {
    profile.discord_interest = answers.discord_interest.toLowerCase() === 'absolutely' ? 'high' : answers.discord_interest.toLowerCase() === 'maybe' ? 'medium' : 'low';
  }
  if (answers.tail_picks) profile.tails_picks = answers.tail_picks.toLowerCase() !== 'never';
  if (answers.referral_reward) {
    profile.referral_reward_likely = answers.referral_reward.toLowerCase() === 'definitely';
  }
  if (answers.content_preference) profile.content_preference = answers.content_preference.toLowerCase();

  // ── Timestamp ──────────────────────────────────────────────

  profile.last_survey_at = new Date().toISOString();

  return profile;
}

// POST /api/survey/:id/submit — submit answers, award credits, build profile tags
router.post('/:id/submit', authMiddleware, async (req: Request, res: Response) => {
  try {
    const surveyId = req.params.id;
    const userId = req.user!.userId;
    const { answers } = req.body;

    if (!isUuid(surveyId)) {
      res.status(400).json({ error: 'Invalid survey id' });
      return;
    }

    if (!answers || typeof answers !== 'object') {
      res.status(400).json({ error: 'answers required' });
      return;
    }

    // Verify survey exists and is active
    const { rows: surveys } = await pool.query(
      `SELECT * FROM rm_surveys WHERE id = $1 AND is_active = TRUE`,
      [surveyId]
    );

    if (surveys.length === 0) {
      res.status(404).json({ error: 'Survey not found or inactive' });
      return;
    }

    const survey = surveys[0];

    // Email verification gate. Grace handling remains as a backward-compatible fallback
    // for any legacy accounts that still have a grace window set.
    const { rows: userRows } = await pool.query(
      `SELECT email_verified, grace_expires_at FROM rm_users WHERE id = $1`, [userId]
    );
    if (userRows.length > 0 && !userRows[0].email_verified) {
      const inGrace = userRows[0].grace_expires_at && new Date() < new Date(userRows[0].grace_expires_at);
      if (!inGrace) {
        res.status(403).json({ error: 'Email verification required', needsVerification: true });
        return;
      }
    }

    // Enforce one-per-week: check if user submitted ANY survey in the last 7 days
    const { rows: recentSubmit } = await pool.query(
      `SELECT id FROM rm_survey_responses
       WHERE user_id = $1 AND created_at > NOW() - INTERVAL '7 days'
       LIMIT 1`,
      [userId]
    );
    if (recentSubmit.length > 0) {
      res.status(429).json({ error: 'You can only complete one survey per week. Check back next week!' });
      return;
    }

    // Atomic insert — ON CONFLICT prevents double-submit race condition
    const { rows: inserted } = await pool.query(
      `INSERT INTO rm_survey_responses (survey_id, user_id, answers, credit_awarded)
       VALUES ($1, $2, $3, TRUE)
       ON CONFLICT (survey_id, user_id) DO NOTHING
       RETURNING id`,
      [surveyId, userId, JSON.stringify(answers)]
    );

    if (inserted.length === 0) {
      res.status(409).json({ error: 'Survey already completed' });
      return;
    }

    // Build profile tags from answers and merge into user preferences
    const profileTags = buildProfileTags(answers);
    const creditsAwarded = resolveSurveyReward(survey.credit_reward);

    await pool.query(
      `UPDATE rm_users
       SET preferences = COALESCE(preferences, '{}'::jsonb) || $1::jsonb,
           survey_bonus_forecasts = survey_bonus_forecasts + $2,
           updated_at = NOW()
       WHERE id = $3`,
      [JSON.stringify(profileTags), creditsAwarded, userId]
    );

    const balance = await getPickBalance(userId);
    const totalAfter =
      (balance.daily_free_forecasts || 0) +
      (balance.daily_pass_valid ? balance.daily_pass_picks : 0) +
      (balance.signup_bonus_forecasts || 0) +
      (balance.survey_bonus_forecasts || 0) +
      (balance.single_picks || 0);

    await recordLedgerEntry(userId, creditsAwarded, 'SURVEY_REWARD', totalAfter, {
      surveyId,
      creditReward: creditsAwarded,
    }).catch((err) => { console.error('[survey] Ledger insert failed:', err.message); });

    res.json({
      ok: true,
      creditsAwarded,
      newBalance: totalAfter,
      forecastBalance: totalAfter,
      forecast_balance: totalAfter,
    });
  } catch (err) {
    console.error('Survey submit error:', err);
    res.status(500).json({ error: 'Failed to submit survey' });
  }
});

export default router;
