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

export interface MobileEngagementSummary {
  configured: boolean;
  activeUsers: number;
  totalGraphHours: number;
  totalAutotaskHours: number;
  hoursPerActiveUser: number;
}

const ALLOWED_PERIODS = ['D7', 'D30', 'D90'] as const;
type AllowedPeriod = (typeof ALLOWED_PERIODS)[number];

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 },
    );
  }

  try {
    // NOTE (TZ-02 carve-out, see REQUIREMENTS.md): engagement_snapshots
    // are bucketed by UTC at sync time by lib/services/engagement-sync-service.ts.
    // Per-user-tz snapshot bucketing is deferred to a future phase
    // (would require either per-request re-bucketing — expensive — or
    // per-user snapshot rebuild — doubles storage). The ≤24h drift on
    // active-users D7/D30/D90 + total MS Graph hours is acceptable for
    // an admin-overview surface. Only the rolling time_entries window
    // below is migrated to user-tz.
    // Get the latest snapshot date for this period
    const latestResult = await postgresClient.query(
      `SELECT MAX(period_end) AS latest_date FROM engagement_snapshots WHERE period_type = $1`,
      [period],
    );
    const latestDate = latestResult.rows[0]?.latest_date;

    if (!latestDate) {
      return NextResponse.json({
        configured: isMsgraphConfigured(),
        activeUsers: 0,
        totalGraphHours: 0,
        totalAutotaskHours: 0,
        hoursPerActiveUser: 0,
      } satisfies MobileEngagementSummary);
    }

    const intervalMap: Record<AllowedPeriod, string> = {
      D7: '7 days',
      D30: '30 days',
      D90: '90 days',
    };
    const interval = intervalMap[period];

    // Exclude pure-outbound service/automation accounts — copy verbatim from
    // app/api/engagement/summary/route.ts:42-49
    const notAutomatedFilter = `NOT (
      es.user_email IS NOT NULL
      AND COALESCE(es.emails_received, 0) = 0
      AND COALESCE(es.teams_chat_messages, 0) = 0
      AND COALESCE(es.teams_meetings_attended, 0) = 0
      AND COALESCE(es.teams_calls, 0) = 0
    )`;

    // Active users — count distinct users with any Teams/email activity
    const activeResult = await postgresClient.query(
      `SELECT COUNT(DISTINCT es.user_email) AS count
         FROM engagement_snapshots es
         JOIN graph_users gu ON LOWER(gu.email) = LOWER(es.user_email)
         JOIN (
           SELECT DISTINCT ON (LOWER(email)) id, email
           FROM resources
           WHERE (is_deleted = false OR is_deleted IS NULL) AND email IS NOT NULL
           ORDER BY LOWER(email), id
         ) r ON LOWER(r.email) = LOWER(gu.email)
        WHERE es.period_type = $1 AND es.period_end = $2
          AND (es.teams_meetings_attended > 0 OR es.teams_chat_messages > 0 OR es.emails_sent > 0)
          AND gu.account_enabled = true
          AND LOWER(gu.email) LIKE '%@wulfconsulting.%'
          AND LOWER(gu.email) NOT LIKE '%#ext#%'
          AND ${notAutomatedFilter}`,
      [period, latestDate],
    );
    const activeUsers = parseInt(activeResult.rows[0]?.count ?? '0', 10);

    // Total Graph hours — sum(audio_duration_seconds + meeting_duration_seconds) / 3600
    const graphHoursResult = await postgresClient.query(
      `SELECT COALESCE(SUM(
          COALESCE(es.audio_duration_seconds, 0) + COALESCE(es.meeting_duration_seconds, 0)
        ), 0) AS total_seconds
         FROM engagement_snapshots es
         JOIN graph_users gu ON LOWER(gu.email) = LOWER(es.user_email)
         JOIN (
           SELECT DISTINCT ON (LOWER(email)) id, email
           FROM resources
           WHERE (is_deleted = false OR is_deleted IS NULL) AND email IS NOT NULL
           ORDER BY LOWER(email), id
         ) r ON LOWER(r.email) = LOWER(gu.email)
        WHERE es.period_type = $1 AND es.period_end = $2
          AND gu.account_enabled = true
          AND LOWER(gu.email) LIKE '%@wulfconsulting.%'
          AND LOWER(gu.email) NOT LIKE '%#ext#%'
          AND ${notAutomatedFilter}`,
      [period, latestDate],
    );
    const totalGraphSeconds = parseFloat(graphHoursResult.rows[0]?.total_seconds ?? '0');
    const totalGraphHours = Math.round((totalGraphSeconds / 3600) * 10) / 10;

    // Total Autotask hours — SUM(time_entries.hours_worked) for matched resources in the period.
    // NOTE: ${interval} is interpolated, NOT parameterized — safe because period is whitelisted
    // to one of ['D7','D30','D90'] and interval is looked up from a static map (not user input).
    // TZ-02 (Phase 7.1): the rolling window is anchored to "now" in the calling
    // user's tz. tz is parameterized as $1 (no SQL interpolation).
    const atHoursResult = await postgresClient.query(
      `SELECT COALESCE(SUM(te.hours_worked), 0) AS total_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 AT TIME ZONE 'UTC' AT TIME ZONE $1) >= (NOW() AT TIME ZONE $1) - INTERVAL '${interval}'
          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#%'`,
      [tz],
    );
    const totalAutotaskHours = Math.round(parseFloat(atHoursResult.rows[0]?.total_hours ?? '0') * 10) / 10;

    // Hours per active user — 0 when activeUsers === 0 (UI renders "—")
    const hoursPerActiveUser =
      activeUsers === 0 ? 0 : Math.round((totalAutotaskHours / activeUsers) * 10) / 10;

    return NextResponse.json({
      configured: isMsgraphConfigured(),
      activeUsers,
      totalGraphHours,
      totalAutotaskHours,
      hoursPerActiveUser,
    } satisfies MobileEngagementSummary);
  } catch (error) {
    console.error('GET /api/mobile/engagement/summary failed:', error);
    return NextResponse.json(
      {
        error: 'Failed to fetch engagement summary',
        message: error instanceof Error ? error.message : 'unknown',
      },
      { status: 500 },
    );
  }
}
