const request = require('supertest');

// Mock Redis
const mockRedis = { get: jest.fn(), set: jest.fn(), hset: jest.fn(), hgetall: jest.fn(), expire: jest.fn() };
jest.mock('../../src/utils/redis', () => ({ getRedisClient: () => mockRedis }));

// Mock Supabase
const mockSupabaseFrom = jest.fn();
const mockSupabaseAuth = { getUser: jest.fn() };
jest.mock('../../src/utils/supabase', () => ({
  getSupabaseClient: () => ({ auth: mockSupabaseAuth, from: mockSupabaseFrom }),
  getSupabaseServiceClient: () => ({ auth: mockSupabaseAuth, from: mockSupabaseFrom }),
}));

jest.mock('axios');

const app = require('../../src/app');

beforeEach(() => {
  jest.clearAllMocks();
  mockRedis.get.mockResolvedValue(null);
  mockRedis.set.mockResolvedValue('OK');
  mockRedis.hset.mockResolvedValue(1);
  mockRedis.hgetall.mockResolvedValue({});
  mockRedis.expire.mockResolvedValue(1);
});

describe('GET /api/movements', () => {
  test('returns movements for today', async () => {
    const movements = [
      { player: 'Nikola Jokic', stat_type: 'points', book: 'draftkings', baseline_line: 26.5, current_line: 27.5, movement: 1.0, direction: 'up', sharp_indicator: 'sharp_action' },
    ];
    mockSupabaseFrom.mockReturnValue({
      select: () => ({
        eq: () => ({
          ilike: () => ({
            eq: () => Promise.resolve({ data: movements }),
          }),
        }),
      }),
    });

    // Simple mock: just return movements from Supabase
    mockSupabaseFrom.mockImplementation((table) => {
      if (table === 'line_movements') {
        return {
          select: () => ({
            eq: () => Promise.resolve({ data: movements }),
          }),
        };
      }
      return { select: () => ({ eq: () => Promise.resolve({ data: [] }) }) };
    });

    const res = await request(app).get('/api/movements').expect(200);
    expect(res.body.game_date).toBeDefined();
    expect(Array.isArray(res.body.movements)).toBe(true);
  });
});

describe('GET /api/alerts', () => {
  test('returns 401 without auth', async () => {
    const res = await request(app).get('/api/alerts').expect(401);
    expect(res.body.error).toContain('Authentication');
  });

  test('returns 403 for free tier', async () => {
    mockSupabaseAuth.getUser.mockResolvedValue({
      data: { user: { id: 'u1', email: 'free@test.com' } },
      error: null,
    });
    mockSupabaseFrom.mockImplementation((table) => {
      if (table === 'users') {
        return {
          select: () => ({
            eq: () => ({
              single: () => Promise.resolve({
                data: { id: 'u1', email: 'free@test.com', tier: 'free', scan_count: 0 },
                error: null,
              }),
            }),
          }),
        };
      }
      return { select: () => ({ eq: () => Promise.resolve({ data: [] }) }) };
    });

    const res = await request(app)
      .get('/api/alerts')
      .set('Authorization', 'Bearer valid-token')
      .expect(403);
    expect(res.body.error).toContain('Analyst and Desk');
  });

  test('returns alerts for paid tier user', async () => {
    const alerts = [
      { id: 'a1', alert_type: 'player_scratched', player: 'X', detail: 'scratched', is_read: false, created_at: '2026-03-21T18:00:00Z' },
    ];
    mockSupabaseAuth.getUser.mockResolvedValue({
      data: { user: { id: 'u2', email: 'paid@test.com' } },
      error: null,
    });
    mockSupabaseFrom.mockImplementation((table) => {
      if (table === 'users') {
        return {
          select: () => ({
            eq: () => ({
              single: () => Promise.resolve({
                data: { id: 'u2', email: 'paid@test.com', tier: 'analyst', scan_count: 10 },
                error: null,
              }),
            }),
          }),
        };
      }
      if (table === 'cascade_alerts') {
        return {
          select: (sel, opts) => {
            if (opts?.head) {
              return { eq: () => ({ eq: () => Promise.resolve({ count: 1 }) }) };
            }
            return {
              eq: () => ({
                eq: () => ({
                  order: () => Promise.resolve({ data: alerts, error: null }),
                }),
              }),
            };
          },
        };
      }
      return { select: () => ({ eq: () => Promise.resolve({ data: [] }) }) };
    });

    const res = await request(app)
      .get('/api/alerts')
      .set('Authorization', 'Bearer valid-token')
      .expect(200);

    expect(res.body.alerts).toHaveLength(1);
    expect(res.body.alerts[0].alert_type).toBe('player_scratched');
  });
});

describe('PATCH /api/alerts/:id/read', () => {
  test('marks alert as read', async () => {
    mockSupabaseAuth.getUser.mockResolvedValue({
      data: { user: { id: 'u2', email: 'paid@test.com' } },
      error: null,
    });
    mockSupabaseFrom.mockImplementation((table) => {
      if (table === 'users') {
        return {
          select: () => ({
            eq: () => ({
              single: () => Promise.resolve({
                data: { id: 'u2', email: 'paid@test.com', tier: 'desk', scan_count: 0 },
                error: null,
              }),
            }),
          }),
        };
      }
      if (table === 'cascade_alerts') {
        return {
          update: () => ({
            eq: () => ({
              eq: () => ({
                select: () => ({
                  single: () => Promise.resolve({ data: { id: 'a1', is_read: true }, error: null }),
                }),
              }),
            }),
          }),
        };
      }
      return {};
    });

    const res = await request(app)
      .patch('/api/alerts/a1/read')
      .set('Authorization', 'Bearer valid-token')
      .expect(200);

    expect(res.body.is_read).toBe(true);
  });

  test('returns 404 for nonexistent alert', async () => {
    mockSupabaseAuth.getUser.mockResolvedValue({
      data: { user: { id: 'u2', email: 'paid@test.com' } },
      error: null,
    });
    mockSupabaseFrom.mockImplementation((table) => {
      if (table === 'users') {
        return {
          select: () => ({
            eq: () => ({
              single: () => Promise.resolve({
                data: { id: 'u2', email: 'paid@test.com', tier: 'analyst', scan_count: 0 },
                error: null,
              }),
            }),
          }),
        };
      }
      if (table === 'cascade_alerts') {
        return {
          update: () => ({
            eq: () => ({
              eq: () => ({
                select: () => ({
                  single: () => Promise.resolve({ data: null, error: { message: 'not found' } }),
                }),
              }),
            }),
          }),
        };
      }
      return {};
    });

    const res = await request(app)
      .patch('/api/alerts/nonexistent/read')
      .set('Authorization', 'Bearer valid-token')
      .expect(404);

    expect(res.body.error).toContain('not found');
  });
});
