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

// ─── Company filter helper (preserved verbatim from legacy route) ─────────────

async function getMobileCompanyFilter(): Promise<{ join: string; condition: string }> {
  try {
    const result = await postgresClient.query(
      `SELECT setting_key, setting_value FROM kiosk_settings WHERE setting_key IN ('mobile_company_category_ids', 'mobile_excluded_company_ids')`
    );
    const map: Record<string, string> = {};
    result.rows.forEach((r: any) => { map[r.setting_key] = r.setting_value || ''; });

    const catIds = (map['mobile_company_category_ids'] || '1')
      .split(',').map((s: string) => parseInt(s.trim(), 10)).filter((n: number) => !isNaN(n));
    const exclIds = (map['mobile_excluded_company_ids'] || '')
      .split(',').map((s: string) => parseInt(s.trim(), 10)).filter((n: number) => !isNaN(n));

    const catCond = catIds.length > 0 ? `c.company_category_id IN (${catIds.join(',')})` : 'true';
    const exclCond = exclIds.length > 0 ? `c.id NOT IN (${exclIds.join(',')})` : '';
    const condition = [catCond, exclCond].filter(Boolean).join(' AND ');

    return { join: 'INNER JOIN companies c ON c.id = t.company_id', condition };
  } catch (error) {
    console.error('Error fetching mobile company filter:', error);
    return { join: 'INNER JOIN companies c ON c.id = t.company_id', condition: 'c.company_category_id = 1' };
  }
}

// ─── Exported response interfaces ────────────────────────────────────────────

export interface MobileTicket {
  id: number;
  ticket_number: string;
  title: string;
  status: number;
  priority: number;
  create_date: string;
  last_activity_date: string;
  due_date_time: string | null;
  queue_id: number;
  queue_label: string;
  company_name: string;
  assigned_to: string;
}

export interface MobileTicketListResponse {
  tickets: MobileTicket[];
  nextCursor: string | null;
  hasMore: boolean;
}

// ─── Cursor encode/decode helpers (not exported — D-09) ──────────────────────

interface CursorPayload { last_activity_date: string; id: number; }

function encodeCursor(p: CursorPayload): string {
  return Buffer.from(JSON.stringify(p), 'utf8').toString('base64');
}

function decodeCursor(raw: string | null): CursorPayload | null {
  if (!raw) return null;
  try {
    const parsed = JSON.parse(Buffer.from(raw, 'base64').toString('utf8'));
    if (typeof parsed?.last_activity_date === 'string' && typeof parsed?.id === 'number') {
      return parsed as CursorPayload;
    }
    return null;
  } catch { return null; }
}

// ─── Default status filter: Open (1) + In Progress (8) + Waiting (7) ─────────
// Matches the legacy route's `t.status != 5` default behaviour for managers.
const DEFAULT_STATUSES = [1, 8, 7];

// ─── GET handler ──────────────────────────────────────────────────────────────

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

  try {
    const { searchParams } = request.nextUrl;

    // Parse query params
    const q = searchParams.get('q') ?? '';
    const statusParam = searchParams.get('status');
    const priorityParam = searchParams.get('priority');
    const queueParam = searchParams.get('queue');
    const mineParam = searchParams.get('mine');
    const cursorParam = searchParams.get('cursor');

    // Server-side limit cap — D-11
    const limit = Math.min(25, Math.max(1, parseInt(searchParams.get('limit') ?? '25')));

    // Status: default to [1, 8, 7] when param absent; empty string = no filter
    let statusIds: number[] = DEFAULT_STATUSES;
    if (statusParam !== null) {
      if (statusParam === '') {
        statusIds = [];
      } else {
        const parsed = statusParam.split(',').map(s => parseInt(s.trim(), 10)).filter(n => !isNaN(n));
        statusIds = parsed.length > 0 ? parsed : DEFAULT_STATUSES;
      }
    }

    // Priority: comma-separated ints; absent = no filter
    const priorityIds: number[] = priorityParam
      ? priorityParam.split(',').map(s => parseInt(s.trim(), 10)).filter(n => !isNaN(n))
      : [];

    // Queue: single int; absent = no filter
    const queueId: number | null = queueParam ? parseInt(queueParam, 10) : null;

    // Mine: filter by session user's email
    const mine = mineParam === '1';

    // Cursor: decode; null if missing or malformed
    const cursor = decodeCursor(cursorParam);

    // Build query
    const { condition: companyCondition } = await getMobileCompanyFilter();

    const conditions: string[] = [
      't.is_deleted = false',
      companyCondition,
    ];
    const params: unknown[] = [];

    // Status filter (always applied — defaults to [1, 8, 7] when no param)
    if (statusIds.length > 0) {
      params.push(statusIds);
      conditions.push(`t.status = ANY($${params.length}::int[])`);
    }

    // Search
    if (q) {
      params.push(`%${q}%`);
      conditions.push(`(t.title ILIKE $${params.length} OR t.ticket_number ILIKE $${params.length} OR c.company_name ILIKE $${params.length})`);
    }

    // Priority filter
    if (priorityIds.length > 0) {
      params.push(priorityIds);
      conditions.push(`t.priority = ANY($${params.length}::int[])`);
    }

    // Queue filter
    if (queueId !== null && !isNaN(queueId)) {
      params.push(queueId);
      conditions.push(`t.queue_id = $${params.length}`);
    }

    // Mine filter — email comes from verified session, never from query string (T-04-05)
    if (mine && session?.user?.email) {
      params.push(session.user.email);
      conditions.push(`LOWER(r.email) = LOWER($${params.length})`);
    }

    // Cursor seek predicate — keyset pagination on (last_activity_date DESC, id DESC)
    if (cursor) {
      params.push(cursor.last_activity_date);
      params.push(cursor.id);
      conditions.push(`(t.last_activity_date, t.id) < ($${params.length - 1}::timestamp, $${params.length}::int)`);
    }

    const where = conditions.join(' AND ');

    // Fetch limit+1 rows to detect hasMore without a COUNT query
    const result = await postgresClient.query(`
      SELECT t.id, t.ticket_number, t.title, t.status, t.priority,
             t.create_date, t.last_activity_date, t.due_date_time,
             t.queue_id, q.label AS queue_label,
             c.company_name,
             COALESCE(r.first_name || ' ' || r.last_name, '') AS assigned_to
      FROM tickets t
      INNER JOIN companies c ON c.id = t.company_id
      LEFT JOIN queues q ON q.value = t.queue_id
      LEFT JOIN resources r ON r.id = t.assigned_resource_id
      WHERE ${where}
      ORDER BY t.last_activity_date DESC NULLS LAST, t.id DESC
      LIMIT ${limit + 1}
    `, params);

    const rows = result.rows;
    const hasMore = rows.length > limit;
    const sliced = hasMore ? rows.slice(0, limit) : rows;

    const tickets: MobileTicket[] = sliced.map(row => ({
      id: row.id,
      ticket_number: row.ticket_number,
      title: row.title,
      status: row.status,
      priority: row.priority,
      create_date: row.create_date,
      last_activity_date: row.last_activity_date,
      due_date_time: row.due_date_time ?? null,
      queue_id: row.queue_id,
      queue_label: row.queue_label ?? '',
      company_name: row.company_name ?? '',
      assigned_to: row.assigned_to ?? '',
    }));

    const nextCursor = hasMore
      ? encodeCursor({
          last_activity_date: tickets[tickets.length - 1].last_activity_date,
          id: tickets[tickets.length - 1].id,
        })
      : null;

    return NextResponse.json({ tickets, nextCursor, hasMore } satisfies MobileTicketListResponse);
  } catch (error) {
    console.error('GET /api/mobile/tickets failed:', error);
    return NextResponse.json(
      { error: 'Failed to fetch tickets', message: error instanceof Error ? error.message : 'unknown' },
      { status: 500 },
    );
  }
}
