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

const router = Router();

const PER_PLAYER_UNLOCK_ENABLED = () => process.env.FEATURE_PLAYER_PROPS_PER_PLAYER_UNLOCK === 'true';
const MLB_PROP_CONTEXT_V2 = () => process.env.MLB_PROP_CONTEXT_V2 !== 'false';

function computeTotalBalance(balance: {
  single_picks: number;
  signup_bonus_forecasts?: number;
  survey_bonus_forecasts?: number;
  daily_pass_picks: number;
  daily_pass_valid: boolean;
  daily_free_forecasts: number;
}): number {
  return (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;
}

function buildMlbPropContext(propPayload: any, league: string | null | undefined): Record<string, any> {
  if (!MLB_PROP_CONTEXT_V2() || (league || '').toLowerCase() !== 'mlb') return {};
  const context = propPayload?.model_context;
  if (!context || typeof context !== 'object') return {};
  return {
    mlbPropContext: {
      kRank: context.k_rank ?? null,
      parkFactor: context.park_factor ?? null,
      weatherImpact: context.weather_impact ?? null,
      handednessSplit: context.handedness_split ?? null,
      lineupCertainty: context.lineup_certainty ?? null,
    },
  };
}

// POST /api/forecast-assets/:assetId/unlock — per-player prop unlock
router.post('/:assetId/unlock', authMiddleware, async (req: Request, res: Response) => {
  try {
    const { assetId } = req.params;
    const userId = req.user!.userId;

    // 1. Feature flag gate
    if (!PER_PLAYER_UNLOCK_ENABLED()) {
      res.status(400).json({ error: 'Per-player prop unlocks are not currently enabled' });
      return;
    }

    if (!isUuid(assetId)) {
      res.status(400).json({ error: 'Invalid player prop asset id' });
      return;
    }

    // 2. Validate asset exists in rm_forecast_precomputed
    const { rows: assetRows } = await pool.query(
      `SELECT id, event_id, forecast_type, team_side, player_name, forecast_payload, confidence_score, league
       FROM rm_forecast_precomputed
       WHERE id = $1 AND forecast_type = 'PLAYER_PROP' AND status = 'ACTIVE'`,
      [assetId]
    );

    if (assetRows.length === 0) {
      res.status(404).json({ error: 'Player prop asset not found or inactive' });
      return;
    }

    const asset = assetRows[0];

    // 3. Idempotency check — already unlocked?
    const { rows: existingUnlocks } = await pool.query(
      'SELECT id FROM rm_player_prop_unlocks WHERE user_id = $1 AND forecast_asset_id = $2',
      [userId, assetId]
    );

    if (existingUnlocks.length > 0) {
      // Already unlocked — return full payload without charging
      const bal = await getPickBalance(userId);
      res.json({
        assetId: asset.id,
        eventId: asset.event_id,
        playerName: asset.player_name,
        teamSide: asset.team_side,
        payload: asset.forecast_payload,
        confidence: asset.confidence_score,
        locked: false,
        forecastBalance: computeTotalBalance(bal),
        forecast_balance: computeTotalBalance(bal),
        ...buildMlbPropContext(asset.forecast_payload, asset.league),
      });
      return;
    }

    // 4. User validation
    const user = await findUserById(userId);
    if (!user) {
      res.status(404).json({ error: 'User not found' });
      return;
    }

    const isRainMan = user.is_weatherman;

    // Email verification gate (skip for weathermen)
    if (!isRainMan && !user.email_verified && !isInGracePeriod(user)) {
      res.status(403).json({
        error: 'Email verification required',
        needsVerification: true,
        message: 'Verify your email to unlock player props.',
      });
      return;
    }

    // 5. Balance check (skip for weathermen)
    if (!isRainMan) {
      await ensureDailyGrant(userId);
      const balance = await getPickBalance(userId);
      const total = computeTotalBalance(balance);
      if (total <= 0) {
        res.status(402).json({
          error: 'No forecasts remaining',
          message: 'Get more forecasts to unlock this player prop',
          options: [
            { type: 'single_pick', label: 'Single Forecast', price: '$1', picks: 1 },
            { type: 'daily_pass', label: 'Day Pass (999 Forecasts)', price: '$4.99', picks: 999 },
          ],
        });
        return;
      }

    }

    // 6. Record unlock first so concurrent requests cannot double-charge this asset.
    const insertUnlock = await pool.query(
      `INSERT INTO rm_player_prop_unlocks (user_id, forecast_asset_id, cost_forecasts, source, was_weatherman)
       VALUES ($1, $2, $3, $4, $5)
       ON CONFLICT (user_id, forecast_asset_id) DO NOTHING`,
      [userId, assetId, isRainMan ? 0 : 1, 'per_player', isRainMan]
    );

    if (!isRainMan && !insertUnlock.rowCount) {
      const bal = await getPickBalance(userId);
      res.json({
        assetId: asset.id,
        eventId: asset.event_id,
        playerName: asset.player_name,
        teamSide: asset.team_side,
        payload: asset.forecast_payload,
        confidence: asset.confidence_score,
        locked: false,
        forecastBalance: computeTotalBalance(bal),
        forecast_balance: computeTotalBalance(bal),
        ...buildMlbPropContext(asset.forecast_payload, asset.league),
      });
      return;
    }

    if (!isRainMan) {
      const { success, source } = await deductPick(userId);
      if (!success) {
        await pool.query(
          'DELETE FROM rm_player_prop_unlocks WHERE user_id = $1 AND forecast_asset_id = $2',
          [userId, assetId],
        );
        res.status(402).json({ error: 'Failed to deduct forecast' });
        return;
      }

      const newBalance = await getPickBalance(userId);
      await recordLedgerEntry(userId, -1, 'PLAYER_PROP_UNLOCK', computeTotalBalance(newBalance), {
        eventId: asset.event_id,
        assetId,
        playerName: asset.player_name,
        teamSide: asset.team_side,
        source,
      });
    }

    // 7. Return full payload
    const finalBal = await getPickBalance(userId);
    res.json({
      assetId: asset.id,
      eventId: asset.event_id,
      playerName: asset.player_name,
      teamSide: asset.team_side,
      payload: asset.forecast_payload,
      confidence: asset.confidence_score,
      locked: false,
      forecastBalance: computeTotalBalance(finalBal),
      forecast_balance: computeTotalBalance(finalBal),
      ...buildMlbPropContext(asset.forecast_payload, asset.league),
    });
  } catch (err) {
    console.error('Player prop unlock error:', err);
    res.status(500).json({ error: 'Failed to unlock player prop' });
  }
});

export default router;
