import { NextRequest, NextResponse } from 'next/server';
import { requireAuth } from '@/lib/auth-utils';
import { postgresClient } from '@/lib/services/postgres-client';
import { getUserTimezone } from '@/lib/services/user-timezone';

export interface SparklinePoint {
  date: string;  // ISO date string "YYYY-MM-DD"
  hours: number; // total Autotask hours for that day (0 if no entries)
}

export interface EngagementTrendResponse {
  points: SparklinePoint[]; // D7 → 7, D30 → 30, D90 → 90 points
}

const ALLOWED_PERIODS = ['D7', 'D30', 'D90'] as const;
type AllowedPeriod = (typeof ALLOWED_PERIODS)[number];
const PERIOD_DAYS: Record<AllowedPeriod, number> = { D7: 7, D30: 30, D90: 90 };

function parsePeriod(raw: string | null): AllowedPeriod | null {
  if (!raw) return 'D30'; // default per D-04
  return (ALLOWED_PERIODS as readonly string[]).includes(raw) ? (raw as AllowedPeriod) : null;
}

export async function GET(request: NextRequest): Promise<NextResponse> {
  const { session, error: authError } = await requireAuth();
  if (authError) return authError;
  const tz = getUserTimezone(session);

  const { searchParams } = request.nextUrl;
  const period = parsePeriod(searchParams.get('period'));
  if (period === null) {
    return NextResponse.json(
      { error: 'Invalid period', message: "period must be one of 'D7', 'D30', 'D90'" },
      { status: 400 },
    );
  }

  const days = PERIOD_DAYS[period];
  // T-07-03 mitigation: period whitelist bounds the date range to max 90 days.
  // No user-supplied row-count parameter — generate_series produces at most 90 rows.

  try {
    // generate_series ensures every day in the range has a row even when zero hours
    // were logged (D-15: continuous series, no gaps in the sparkline).
    // ${days - 1} is interpolated, NOT parameterized — safe because period is whitelisted
    // to one of ['D7','D30','D90'] and days comes from a static map (not user input).
    // TZ-02 (Phase 7.1): day buckets are aligned to the calling user's
    // IANA timezone via $1 (validated by getUserTimezone). Storage tz
    // for `time_entries.entry_date` remains UTC.
    const sql = `
      WITH day_series AS (
        SELECT generate_series(
          ((NOW() AT TIME ZONE $1) - INTERVAL '${days - 1} days')::date,
          (NOW() AT TIME ZONE $1)::date,
          INTERVAL '1 day'
        )::date AS day
      ),
      daily_hours AS (
        SELECT te.entry_date::date AS day, COALESCE(SUM(te.hours_worked), 0) AS hours
          FROM time_entries te
          JOIN resources r ON r.id = te.resource_id
            AND (r.is_deleted = false OR r.is_deleted IS NULL)
          JOIN graph_users gu ON LOWER(gu.email) = LOWER(r.email)
         WHERE te.entry_date::date >= ((NOW() AT TIME ZONE $1) - INTERVAL '${days - 1} days')::date
           AND te.entry_date::date <= (NOW() AT TIME ZONE $1)::date
           AND (te.is_deleted = false OR te.is_deleted IS NULL)
           AND gu.account_enabled = true
           AND LOWER(gu.email) LIKE '%@wulfconsulting.%'
           AND LOWER(gu.email) NOT LIKE '%#ext#%'
         GROUP BY te.entry_date::date
      )
      SELECT to_char(ds.day, 'YYYY-MM-DD') AS date,
             COALESCE(dh.hours, 0)::numeric AS hours
        FROM day_series ds
        LEFT JOIN daily_hours dh ON dh.day = ds.day
       ORDER BY ds.day ASC
    `;

    const result = await postgresClient.query(sql, [tz]);

    const points: SparklinePoint[] = result.rows.map((row) => ({
      date: String(row.date),
      hours: Math.round(parseFloat(row.hours ?? '0') * 10) / 10,
    }));

    return NextResponse.json({ points } satisfies EngagementTrendResponse);
  } catch (error) {
    console.error('GET /api/mobile/engagement/trend failed:', error);
    return NextResponse.json(
      {
        error: 'Failed to fetch engagement trend',
        message: error instanceof Error ? error.message : 'unknown',
      },
      { status: 500 },
    );
  }
}
