import { NextRequest, NextResponse } from 'next/server';
import { postgresClient } from '@/lib/services/postgres-client';
import { isZoomConfigured } from '@/lib/services/zoom-factory';

export async function GET(
  request: NextRequest,
  { params }: { params: Promise<{ userId: string }> }
) {
  const { userId } = await params;
  const periodParam = (request.nextUrl.searchParams.get('period') ?? 'D30').toUpperCase();
  const periodDays = periodParam === 'D7' ? 7 : periodParam === 'D90' ? 90 : 30;

  try {
    // Get user from graph_users
    const userResult = await postgresClient.query(
      `SELECT gu.*,
              (SELECT r2.id FROM resources r2
               WHERE LOWER(r2.email) = LOWER(gu.email)
                 AND (r2.is_deleted = false OR r2.is_deleted IS NULL)
               ORDER BY (SELECT MAX(te.entry_date) FROM time_entries te WHERE te.resource_id = r2.id AND (te.is_deleted = false OR te.is_deleted IS NULL)) DESC NULLS LAST
               LIMIT 1) as autotask_resource_id
       FROM graph_users gu
       WHERE gu.id = $1`,
      [userId]
    );

    if (userResult.rows.length === 0) {
      return NextResponse.json({ error: 'User not found' }, { status: 404 });
    }

    const user = userResult.rows[0];

    // Get all snapshots for this user across periods
    const snapshotsResult = await postgresClient.query(
      `SELECT *
       FROM engagement_snapshots
       WHERE LOWER(user_email) = LOWER($1)
       ORDER BY period_end DESC, period_type`,
      [user.email]
    );

    // Get Autotask hours per period
    const hoursResult = user.autotask_resource_id
      ? await postgresClient.query(
          `SELECT
             SUM(CASE WHEN entry_date >= NOW() - INTERVAL '7 days' THEN hours_worked ELSE 0 END) as hours_d7,
             SUM(CASE WHEN entry_date >= NOW() - INTERVAL '30 days' THEN hours_worked ELSE 0 END) as hours_d30,
             SUM(CASE WHEN entry_date >= NOW() - INTERVAL '90 days' THEN hours_worked ELSE 0 END) as hours_d90,
             SUM(CASE WHEN entry_date >= NOW() - INTERVAL '7 days' AND COALESCE(billable, true) = true THEN hours_worked ELSE 0 END) as billable_d7,
             SUM(CASE WHEN entry_date >= NOW() - INTERVAL '30 days' AND COALESCE(billable, true) = true THEN hours_worked ELSE 0 END) as billable_d30,
             SUM(CASE WHEN entry_date >= NOW() - INTERVAL '90 days' AND COALESCE(billable, true) = true THEN hours_worked ELSE 0 END) as billable_d90
           FROM time_entries
           WHERE resource_id = $1
             AND (is_deleted = false OR is_deleted IS NULL)
             AND COALESCE(type, 0) NOT IN (15, 16)
             AND COALESCE(allocation_code_id, 0) NOT IN (91206, 91209)`,
          [user.autotask_resource_id]
        )
      : null;

    const hours = hoursResult?.rows[0];

    // Recent time entries
    const recentEntriesResult = user.autotask_resource_id
      ? await postgresClient.query(
          `SELECT te.entry_date, te.hours_worked, te.billable, te.notes, te.title,
                  te.start_date_time, te.end_date_time,
                  COALESCE(c.company_name, tc.company_name) as company_name
           FROM time_entries te
           LEFT JOIN companies c ON c.id = te.company_id
           LEFT JOIN tickets t ON t.id = te.ticket_id
           LEFT JOIN companies tc ON tc.id = t.company_id
           WHERE te.resource_id = $1
             AND (te.is_deleted = false OR te.is_deleted IS NULL)
             AND te.entry_date >= NOW() - ($2 || ' days')::INTERVAL
             AND COALESCE(te.type, 0) NOT IN (15, 16)
             AND COALESCE(te.allocation_code_id, 0) NOT IN (91206, 91209)
           ORDER BY te.entry_date DESC
           LIMIT 500`,
          [user.autotask_resource_id, periodDays]
        )
      : null;

    // Teams meeting detail records (client-attended)
    let recentTeamsMeetings: Array<{
      subject: string | null;
      startTime: string;
      durationMinutes: number | null;
      attendeeCount: number;
      clientAttendeeCount: number;
      hasClientAttendees: boolean;
      clientCompanies: string[];
      participantNames: string[];
    }> = [];
    try {
      const teamsMeetingsResult = await postgresClient.query(
        `SELECT tm.subject, tm.start_time, tm.duration_minutes,
                tm.attendee_count, tm.client_attendee_count, tm.has_client_attendees,
                ARRAY_REMOVE(ARRAY_AGG(DISTINCT co.company_name), NULL) AS client_companies,
                ARRAY_REMOVE(ARRAY_AGG(DISTINCT COALESCE(tma.attendee_name, tma.attendee_email)), NULL) AS participant_names
         FROM teams_meetings tm
         LEFT JOIN teams_meeting_attendees tma ON tma.meeting_id = tm.id
         LEFT JOIN companies co ON co.id = tma.matched_company_id
         WHERE LOWER(tm.user_email) = LOWER($1)
           AND tm.start_time >= NOW() - ($2 || ' days')::INTERVAL
         GROUP BY tm.id
         ORDER BY tm.start_time DESC
         LIMIT 200`,
        [user.email, periodDays]
      );
      recentTeamsMeetings = teamsMeetingsResult.rows.map(r => ({
        subject: r.subject,
        startTime: r.start_time,
        durationMinutes: r.duration_minutes,
        attendeeCount: r.attendee_count,
        clientAttendeeCount: r.client_attendee_count,
        hasClientAttendees: r.has_client_attendees,
        clientCompanies: r.client_companies ?? [],
        participantNames: r.participant_names ?? [],
      }));
    } catch {
      // teams_meetings table may not exist yet
    }

    // Peer max benchmarks — highest value across all active employees for this period
    const peerMaxResult = await postgresClient.query(
      `SELECT
         MAX(h.hours_total)    as max_hours,
         MAX(h.hours_billable) as max_billable_hours,
         MAX(m.meeting_count)  as max_meetings,
         MAX(m.client_meetings)as max_client_meetings,
         MAX(s.messages)       as max_messages,
         MAX(s.emails)         as max_emails,
         MAX(zc.calls)         as max_calls
       FROM (
         SELECT resource_id,
           SUM(hours_worked) as hours_total,
           SUM(CASE WHEN COALESCE(billable, true) = true THEN hours_worked ELSE 0 END) as hours_billable
         FROM time_entries
         WHERE (is_deleted = false OR is_deleted IS NULL)
           AND entry_date >= NOW() - ($1 || ' days')::INTERVAL
           AND COALESCE(type, 0) NOT IN (15, 16)
           AND COALESCE(allocation_code_id, 0) NOT IN (91206, 91209)
         GROUP BY resource_id
       ) h
       CROSS JOIN (
         SELECT user_email,
           COUNT(*) as meeting_count,
           SUM(CASE WHEN has_client_attendees THEN 1 ELSE 0 END) as client_meetings
         FROM teams_meetings
         WHERE start_time >= NOW() - ($1 || ' days')::INTERVAL
         GROUP BY user_email
       ) m
       CROSS JOIN (
         SELECT user_email,
           MAX(teams_chat_messages + teams_private_messages) as messages,
           MAX(emails_sent) as emails
         FROM engagement_snapshots
         WHERE period_type = $2
         GROUP BY user_email
       ) s
       CROSS JOIN (
         SELECT resource_email,
           COUNT(*) as calls
         FROM zoom_calls
         WHERE call_status = 'completed'
           AND start_time >= NOW() - ($1 || ' days')::INTERVAL
         GROUP BY resource_email
       ) zc`,
      [periodDays, periodParam]
    ).catch(() => null);

    // Previous period values for trend calculation
    const prevPeriodResult = user.autotask_resource_id
      ? await postgresClient.query(
          `SELECT
             SUM(hours_worked) as prev_hours,
             SUM(CASE WHEN COALESCE(billable, true) = true THEN hours_worked ELSE 0 END) as prev_billable
           FROM time_entries
           WHERE resource_id = $1
             AND (is_deleted = false OR is_deleted IS NULL)
             AND entry_date >= NOW() - ($2 || ' days')::INTERVAL * 2
             AND entry_date <  NOW() - ($2 || ' days')::INTERVAL
             AND COALESCE(type, 0) NOT IN (15, 16)
             AND COALESCE(allocation_code_id, 0) NOT IN (91206, 91209)`,
          [user.autotask_resource_id, periodDays]
        ).catch(() => null)
      : null;

    const prevMeetingsResult = await postgresClient.query(
      `SELECT COUNT(*) as prev_meetings,
              SUM(CASE WHEN has_client_attendees THEN 1 ELSE 0 END) as prev_client_meetings
       FROM teams_meetings
       WHERE LOWER(user_email) = LOWER($1)
         AND start_time >= NOW() - ($2 || ' days')::INTERVAL * 2
         AND start_time <  NOW() - ($2 || ' days')::INTERVAL`,
      [user.email, periodDays]
    ).catch(() => null);

    const prevZoomResult = await postgresClient.query(
      `SELECT COUNT(*) as prev_calls
       FROM zoom_calls
       WHERE LOWER(resource_email) = LOWER($1)
         AND call_status = 'completed'
         AND start_time >= NOW() - ($2 || ' days')::INTERVAL * 2
         AND start_time <  NOW() - ($2 || ' days')::INTERVAL`,
      [user.email, periodDays]
    ).catch(() => null);

    // Mimecast real-time email counts
    const mimecastEmailsResult = await postgresClient.query(
      `SELECT
         COUNT(*) FILTER (WHERE LOWER(sender_address) = LOWER($1) AND direction IN ('outbound','internal') AND sent_datetime >= NOW() - INTERVAL '7 days')  AS sent_d7,
         COUNT(*) FILTER (WHERE LOWER(sender_address) = LOWER($1) AND direction IN ('outbound','internal') AND sent_datetime >= NOW() - INTERVAL '30 days') AS sent_d30,
         COUNT(*) FILTER (WHERE LOWER(sender_address) = LOWER($1) AND direction IN ('outbound','internal') AND sent_datetime >= NOW() - INTERVAL '90 days') AS sent_d90,
         COUNT(*) FILTER (WHERE LOWER(recipient_address) = LOWER($1) AND direction IN ('inbound','internal') AND status IN ('archived','accepted') AND sent_datetime >= NOW() - INTERVAL '7 days')  AS received_d7,
         COUNT(*) FILTER (WHERE LOWER(recipient_address) = LOWER($1) AND direction IN ('inbound','internal') AND status IN ('archived','accepted') AND sent_datetime >= NOW() - INTERVAL '30 days') AS received_d30,
         COUNT(*) FILTER (WHERE LOWER(recipient_address) = LOWER($1) AND direction IN ('inbound','internal') AND status IN ('archived','accepted') AND sent_datetime >= NOW() - INTERVAL '90 days') AS received_d90
       FROM mimecast_messages
       WHERE LOWER(sender_address) = LOWER($1)
          OR (LOWER(recipient_address) = LOWER($1) AND direction IN ('inbound','internal') AND status IN ('archived','accepted'))`,
      [user.email]
    ).catch(() => null);
    const me = mimecastEmailsResult?.rows[0];

    // After-hours meetings (5:30 PM – 7:00 AM America/New_York)
    const afterHoursMeetingsResult = await postgresClient.query(
      `SELECT COUNT(*) as count
       FROM teams_meetings
       WHERE LOWER(user_email) = LOWER($1)
         AND start_time >= NOW() - ($2 || ' days')::INTERVAL
         AND (
           EXTRACT(HOUR FROM start_time AT TIME ZONE 'America/New_York') * 60
             + EXTRACT(MINUTE FROM start_time AT TIME ZONE 'America/New_York') >= 1050
           OR
           EXTRACT(HOUR FROM start_time AT TIME ZONE 'America/New_York') * 60
             + EXTRACT(MINUTE FROM start_time AT TIME ZONE 'America/New_York') < 420
         )`,
      [user.email, periodDays]
    ).catch(() => ({ rows: [{ count: 0 }] }));
    const afterHoursMeetings = parseInt(afterHoursMeetingsResult.rows[0]?.count ?? 0);

    // Daily activity heatmap data
    let dailyActivity: Array<{ date: string; meetings: number; zoomCalls: number; hours: number; meetingMins: number }> = [];
    try {
      const dailyResult = await postgresClient.query(
        `SELECT
           day::date as date,
           COALESCE(SUM(meetings), 0)::int as meetings,
           COALESCE(SUM(zoom_calls), 0)::int as zoom_calls,
           COALESCE(SUM(hours), 0)::float as hours,
           COALESCE(SUM(meeting_mins), 0)::int as meeting_mins
         FROM (
           SELECT DATE(start_time) as day, COUNT(*) as meetings, SUM(duration_minutes) as meeting_mins, 0 as zoom_calls, 0 as hours
           FROM teams_meetings
           WHERE LOWER(user_email) = LOWER($1)
             AND start_time >= NOW() - ($2 || ' days')::INTERVAL
           GROUP BY DATE(start_time)
           UNION ALL
           SELECT DATE(start_time) as day, 0, 0, COUNT(*) as zoom_calls, 0
           FROM zoom_calls
           WHERE LOWER(resource_email) = LOWER($1)
             AND call_status = 'completed'
             AND start_time >= NOW() - ($2 || ' days')::INTERVAL
           GROUP BY DATE(start_time)
           UNION ALL
           SELECT DATE(entry_date) as day, 0, 0, 0, SUM(hours_worked) as hours
           FROM time_entries te
           WHERE te.resource_id = $3
             AND (te.is_deleted = false OR te.is_deleted IS NULL)
             AND entry_date >= NOW() - ($2 || ' days')::INTERVAL
             AND COALESCE(te.type, 0) NOT IN (15, 16)
             AND COALESCE(te.allocation_code_id, 0) NOT IN (91206, 91209)
           GROUP BY DATE(entry_date)
         ) combined
         GROUP BY day
         ORDER BY day`,
        [user.email, periodDays, user.autotask_resource_id]
      );
      dailyActivity = dailyResult.rows.map(r => ({
        date: r.date instanceof Date ? r.date.toISOString().slice(0, 10) : String(r.date).slice(0, 10),
        meetings: Number(r.meetings),
        zoomCalls: Number(r.zoom_calls),
        hours: Number(r.hours),
        meetingMins: Number(r.meeting_mins),
      }));
    } catch {
      // ignore if tables missing
    }

    // Zoom data (only if configured and tables exist)
    let zoomData = null;
    if (isZoomConfigured()) {
      try {
        const email = user.email;

        const [zoomCallsResult, zoomMeetingsResult, zoomTopClientsResult, recentCallsResult, recentMeetingsResult] = await Promise.all([
          postgresClient.query(
            `SELECT
               SUM(CASE WHEN start_time >= NOW() - INTERVAL '7 days' THEN 1 ELSE 0 END) as calls_d7,
               SUM(CASE WHEN start_time >= NOW() - INTERVAL '30 days' THEN 1 ELSE 0 END) as calls_d30,
               SUM(CASE WHEN start_time >= NOW() - INTERVAL '90 days' THEN 1 ELSE 0 END) as calls_d90,
               SUM(CASE WHEN start_time >= NOW() - INTERVAL '7 days' AND (matched_contact_id IS NOT NULL OR matched_company_id IS NOT NULL) THEN 1 ELSE 0 END) as client_calls_d7,
               SUM(CASE WHEN start_time >= NOW() - INTERVAL '30 days' AND (matched_contact_id IS NOT NULL OR matched_company_id IS NOT NULL) THEN 1 ELSE 0 END) as client_calls_d30,
               SUM(CASE WHEN start_time >= NOW() - INTERVAL '90 days' AND (matched_contact_id IS NOT NULL OR matched_company_id IS NOT NULL) THEN 1 ELSE 0 END) as client_calls_d90,
               SUM(CASE WHEN start_time >= NOW() - INTERVAL '7 days' AND direction = 'outbound' THEN 1 ELSE 0 END) as outbound_d7,
               SUM(CASE WHEN start_time >= NOW() - INTERVAL '30 days' AND direction = 'outbound' THEN 1 ELSE 0 END) as outbound_d30,
               SUM(CASE WHEN start_time >= NOW() - INTERVAL '90 days' AND direction = 'outbound' THEN 1 ELSE 0 END) as outbound_d90,
               SUM(CASE WHEN start_time >= NOW() - INTERVAL '7 days' AND direction = 'inbound' THEN 1 ELSE 0 END) as inbound_d7,
               SUM(CASE WHEN start_time >= NOW() - INTERVAL '30 days' AND direction = 'inbound' THEN 1 ELSE 0 END) as inbound_d30,
               SUM(CASE WHEN start_time >= NOW() - INTERVAL '90 days' AND direction = 'inbound' THEN 1 ELSE 0 END) as inbound_d90,
               SUM(CASE WHEN start_time >= NOW() - INTERVAL '7 days' THEN COALESCE(duration_seconds, 0) ELSE 0 END) as duration_d7,
               SUM(CASE WHEN start_time >= NOW() - INTERVAL '30 days' THEN COALESCE(duration_seconds, 0) ELSE 0 END) as duration_d30,
               SUM(CASE WHEN start_time >= NOW() - INTERVAL '90 days' THEN COALESCE(duration_seconds, 0) ELSE 0 END) as duration_d90
             FROM zoom_calls
             WHERE LOWER(resource_email) = LOWER($1)
               AND call_status = 'completed'
               AND COALESCE(duration_seconds, 0) > 0`,
            [email]
          ),
          postgresClient.query(
            `SELECT
               SUM(CASE WHEN start_time >= NOW() - INTERVAL '7 days' THEN 1 ELSE 0 END) as meetings_d7,
               SUM(CASE WHEN start_time >= NOW() - INTERVAL '30 days' THEN 1 ELSE 0 END) as meetings_d30,
               SUM(CASE WHEN start_time >= NOW() - INTERVAL '90 days' THEN 1 ELSE 0 END) as meetings_d90,
               SUM(CASE WHEN start_time >= NOW() - INTERVAL '7 days' AND has_client_attendees = true THEN 1 ELSE 0 END) as client_meetings_d7,
               SUM(CASE WHEN start_time >= NOW() - INTERVAL '30 days' AND has_client_attendees = true THEN 1 ELSE 0 END) as client_meetings_d30,
               SUM(CASE WHEN start_time >= NOW() - INTERVAL '90 days' AND has_client_attendees = true THEN 1 ELSE 0 END) as client_meetings_d90
             FROM zoom_meetings
             WHERE LOWER(host_email) = LOWER($1)`,
            [email]
          ),
          postgresClient.query(
            `SELECT
               co.company_name,
               COUNT(DISTINCT zc.id) as call_count,
               COUNT(DISTINCT zm.id) as meeting_count
             FROM companies co
             LEFT JOIN zoom_calls zc
               ON zc.matched_company_id = co.id
               AND LOWER(zc.resource_email) = LOWER($1)
               AND zc.start_time >= NOW() - INTERVAL '30 days'
             LEFT JOIN zoom_meetings zm
               ON zm.id IN (
                 SELECT zmp.meeting_id FROM zoom_meeting_participants zmp
                 WHERE zmp.matched_company_id = co.id
               )
               AND LOWER(zm.host_email) = LOWER($1)
               AND zm.start_time >= NOW() - INTERVAL '30 days'
             WHERE (zc.id IS NOT NULL OR zm.id IS NOT NULL)
             GROUP BY co.id, co.company_name
             ORDER BY (COUNT(DISTINCT zc.id) + COUNT(DISTINCT zm.id)) DESC
             LIMIT 5`,
            [email]
          ),
          postgresClient.query(
            `SELECT zc.direction, zc.call_status, zc.other_party_name, zc.other_party_number,
                    zc.start_time, zc.duration_seconds,
                    co.company_name
             FROM zoom_calls zc
             LEFT JOIN companies co ON co.id = zc.matched_company_id
             WHERE LOWER(zc.resource_email) = LOWER($1)
               AND zc.call_status = 'completed'
               AND COALESCE(zc.duration_seconds, 0) > 0
             ORDER BY zc.start_time DESC
             LIMIT 30`,
            [email]
          ),
          postgresClient.query(
            `SELECT zm.id, zm.topic, zm.start_time, zm.end_time, zm.duration_minutes,
                    zm.participant_count, zm.client_participant_count, zm.has_client_attendees,
                    ARRAY_REMOVE(ARRAY_AGG(DISTINCT CASE WHEN NOT zmp.is_internal AND zmp.participant_name IS NOT NULL THEN zmp.participant_name ELSE NULL END), NULL) AS external_participant_names,
                    ARRAY_REMOVE(ARRAY_AGG(DISTINCT co.company_name), NULL) AS client_companies
             FROM zoom_meetings zm
             LEFT JOIN zoom_meeting_participants zmp ON zmp.meeting_id = zm.id
             LEFT JOIN companies co ON co.id = zmp.matched_company_id
             WHERE (LOWER(zm.host_email) = LOWER($1)
                OR EXISTS (SELECT 1 FROM zoom_meeting_participants p WHERE p.meeting_id = zm.id AND LOWER(p.participant_email) = LOWER($1)))
               AND zm.start_time >= NOW() - ($2 || ' days')::INTERVAL
             GROUP BY zm.id
             ORDER BY zm.start_time DESC
             LIMIT 100`,
            [email, periodDays]
          ),
        ]);

        const cr = zoomCallsResult.rows[0];
        const mr = zoomMeetingsResult.rows[0];

        zoomData = {
          calls: {
            d7: {
              total: parseInt(cr.calls_d7 ?? 0),
              client: parseInt(cr.client_calls_d7 ?? 0),
              outbound: parseInt(cr.outbound_d7 ?? 0),
              inbound: parseInt(cr.inbound_d7 ?? 0),
              durationSeconds: parseInt(cr.duration_d7 ?? 0),
            },
            d30: {
              total: parseInt(cr.calls_d30 ?? 0),
              client: parseInt(cr.client_calls_d30 ?? 0),
              outbound: parseInt(cr.outbound_d30 ?? 0),
              inbound: parseInt(cr.inbound_d30 ?? 0),
              durationSeconds: parseInt(cr.duration_d30 ?? 0),
            },
            d90: {
              total: parseInt(cr.calls_d90 ?? 0),
              client: parseInt(cr.client_calls_d90 ?? 0),
              outbound: parseInt(cr.outbound_d90 ?? 0),
              inbound: parseInt(cr.inbound_d90 ?? 0),
              durationSeconds: parseInt(cr.duration_d90 ?? 0),
            },
          },
          meetings: {
            d7: { total: parseInt(mr.meetings_d7 ?? 0), withClients: parseInt(mr.client_meetings_d7 ?? 0) },
            d30: { total: parseInt(mr.meetings_d30 ?? 0), withClients: parseInt(mr.client_meetings_d30 ?? 0) },
            d90: { total: parseInt(mr.meetings_d90 ?? 0), withClients: parseInt(mr.client_meetings_d90 ?? 0) },
          },
          topClients: zoomTopClientsResult.rows.map(r => ({
            companyName: r.company_name,
            callCount: parseInt(r.call_count),
            meetingCount: parseInt(r.meeting_count),
          })),
          recentCalls: recentCallsResult.rows.map(r => ({
            direction: r.direction,
            status: r.call_status,
            otherPartyName: r.other_party_name,
            otherPartyNumber: r.other_party_number,
            startTime: r.start_time,
            durationSeconds: r.duration_seconds,
            companyName: r.company_name,
          })),
          recentMeetings: recentMeetingsResult.rows.map(r => {
            const zmStart = new Date(r.start_time).getTime();
            const zmEnd = r.end_time
              ? new Date(r.end_time).getTime()
              : r.duration_minutes
                ? zmStart + r.duration_minutes * 60_000
                : zmStart + 60 * 60_000;
            const zmClientNames: string[] = (r.client_companies ?? []).map((n: string) => n.toLowerCase());
            const toMs = (ts: string | null): number | null => {
              if (!ts) return null;
              const s = ts.toString();
              const normalized = /[Z+\-]\d*$/.test(s.trim()) ? s : s.trim() + 'Z';
              return new Date(normalized).getTime();
            };
            const matched = (recentEntriesResult?.rows ?? []).filter(te => {
              if (r.has_client_attendees && zmClientNames.length > 0) {
                if (!te.company_name) return false;
                const teCo = te.company_name.toLowerCase();
                if (!zmClientNames.some((c: string) => teCo.includes(c) || c.includes(teCo))) return false;
              }
              if (te.start_date_time) {
                const teStart = toMs(te.start_date_time)!;
                const teEnd = te.end_date_time
                  ? toMs(te.end_date_time)!
                  : teStart + te.hours_worked * 3_600_000;
                const tolerance = 30 * 60_000;
                return teStart < zmEnd + tolerance && teEnd > zmStart - tolerance;
              }
              const teDate = new Date((toMs(te.entry_date) ?? 0)).toUTCString().slice(0, 16);
              const zmDate = new Date(r.start_time).toUTCString().slice(0, 16);
              return teDate === zmDate;
            });
            return {
              topic: r.topic,
              startTime: r.start_time,
              endTime: r.end_time,
              durationMinutes: r.duration_minutes,
              participantCount: r.participant_count,
              clientParticipantCount: r.client_participant_count,
              hasClientAttendees: r.has_client_attendees,
              externalParticipantNames: r.external_participant_names ?? [],
              clientCompanies: r.client_companies ?? [],
              matchedEntries: matched.map(te => ({
                hours_worked: te.hours_worked,
                billable: te.billable,
                notes: te.notes,
                title: te.title,
                company_name: te.company_name,
                start_date_time: te.start_date_time,
                end_date_time: te.end_date_time,
              })),
            };
          }),
        };
      } catch {
        // Zoom tables may not exist yet — return null
        zoomData = null;
      }
    }

    // After-hours summary (messages from snapshot for current period, meetings from DB)
    const currentSnap = snapshotsResult.rows.find(s => s.period_type === periodParam);
    const totalMessages = (currentSnap?.teams_chat_messages ?? 0) + (currentSnap?.teams_private_messages ?? 0);
    const totalMeetings = recentTeamsMeetings.length;
    const afterHoursMessages = currentSnap?.after_hours_messages ?? 0;

    return NextResponse.json({
      user: {
        id: user.id,
        displayName: user.display_name,
        email: user.email,
        jobTitle: user.job_title,
        department: user.department,
        accountEnabled: user.account_enabled,
        autotaskResourceId: user.autotask_resource_id,
      },
      afterHours: {
        messages: afterHoursMessages,
        meetings: afterHoursMeetings,
        messagesPct: totalMessages > 0 ? Math.round((afterHoursMessages / totalMessages) * 100) : 0,
        meetingsPct: totalMeetings > 0 ? Math.round((afterHoursMeetings / totalMeetings) * 100) : 0,
      },
      emails: me ? {
        d7:  { sent: parseInt(me.sent_d7  ?? 0), received: parseInt(me.received_d7  ?? 0) },
        d30: { sent: parseInt(me.sent_d30 ?? 0), received: parseInt(me.received_d30 ?? 0) },
        d90: { sent: parseInt(me.sent_d90 ?? 0), received: parseInt(me.received_d90 ?? 0) },
      } : null,
      snapshots: snapshotsResult.rows,
      hours: hours
        ? {
            d7: { total: parseFloat(hours.hours_d7 ?? 0), billable: parseFloat(hours.billable_d7 ?? 0) },
            d30: { total: parseFloat(hours.hours_d30 ?? 0), billable: parseFloat(hours.billable_d30 ?? 0) },
            d90: { total: parseFloat(hours.hours_d90 ?? 0), billable: parseFloat(hours.billable_d90 ?? 0) },
          }
        : null,
      recentEntries: recentEntriesResult?.rows ?? [],
      recentTeamsMeetings: recentTeamsMeetings.map(mtg => {
        const mtgStart = new Date(mtg.startTime).getTime();
        const mtgEnd = mtg.durationMinutes
          ? mtgStart + mtg.durationMinutes * 60_000
          : mtgStart + 60 * 60_000; // assume 1h if unknown
        const mtgClientNames = mtg.clientCompanies.map((n: string) => n.toLowerCase());
        // Normalize a DB timestamp to ms — treat naive timestamps as UTC
        const toMs = (ts: string | null): number | null => {
          if (!ts) return null;
          const s = ts.toString();
          // If no timezone info, append Z so Date parses it as UTC
          const normalized = /[Z+\-]\d*$/.test(s.trim()) ? s : s.trim() + 'Z';
          return new Date(normalized).getTime();
        };
        const matched = (recentEntriesResult?.rows ?? []).filter(te => {
          // Company match: if the meeting has client companies, the time entry must be for one of them
          if (mtg.hasClientAttendees && mtgClientNames.length > 0) {
            if (!te.company_name) return false;
            const teCo = te.company_name.toLowerCase();
            if (!mtgClientNames.some((c: string) => teCo.includes(c) || c.includes(teCo))) return false;
          }
          // Time match
          if (te.start_date_time) {
            const teStart = toMs(te.start_date_time)!;
            const teEnd = te.end_date_time
              ? toMs(te.end_date_time)!
              : teStart + te.hours_worked * 3_600_000;
            const tolerance = 30 * 60_000;
            return teStart < mtgEnd + tolerance && teEnd > mtgStart - tolerance;
          }
          // Fallback: same UTC date
          const teDate = new Date((toMs(te.entry_date) ?? 0)).toUTCString().slice(0, 16);
          const mtgDate = new Date(mtg.startTime).toUTCString().slice(0, 16);
          return teDate === mtgDate;
        });
        return { ...mtg, matchedEntries: matched.map(te => ({
          hours_worked: te.hours_worked,
          billable: te.billable,
          notes: te.notes,
          title: te.title,
          company_name: te.company_name,
          start_date_time: te.start_date_time,
          end_date_time: te.end_date_time,
        })) };
      }),
      meetingCounts: {
        total: recentTeamsMeetings.length,
        withClients: recentTeamsMeetings.filter(m => m.hasClientAttendees).length,
      },
      dailyActivity,
      zoom: zoomData,
      peerMax: peerMaxResult?.rows[0]
        ? {
            hours:        parseFloat(peerMaxResult.rows[0].max_hours ?? 0),
            billableHours:parseFloat(peerMaxResult.rows[0].max_billable_hours ?? 0),
            meetings:     parseInt(peerMaxResult.rows[0].max_meetings ?? 0),
            clientMeetings:parseInt(peerMaxResult.rows[0].max_client_meetings ?? 0),
            messages:     parseInt(peerMaxResult.rows[0].max_messages ?? 0),
            emails:       parseInt(peerMaxResult.rows[0].max_emails ?? 0),
            calls:        parseInt(peerMaxResult.rows[0].max_calls ?? 0),
          }
        : null,
      trend: {
        hours:    parseFloat(prevPeriodResult?.rows[0]?.prev_hours ?? 0),
        billable: parseFloat(prevPeriodResult?.rows[0]?.prev_billable ?? 0),
        meetings: parseInt(prevMeetingsResult?.rows[0]?.prev_meetings ?? 0),
        calls:    parseInt(prevZoomResult?.rows[0]?.prev_calls ?? 0),
      },
    });
  } catch (error) {
    console.error('[ENGAGEMENT-USER-DETAIL] Error:', error);
    return NextResponse.json({ error: 'Failed to fetch user detail' }, { status: 500 });
  }
}
