import { test, expect } from '@playwright/test';
import { getCachedTokens, authHeaders } from './helpers';

const API_URL = process.env.E2E_API_URL || 'http://localhost:3000';

test.describe('CRM Module', () => {
  const adminTokens = getCachedTokens('superAdmin');
  const trainerTokens = getCachedTokens('trainer');

  // -----------------------------------------------------------------------
  // Setup: ensure a default pipeline with stages (clubId=null)
  // -----------------------------------------------------------------------

  test.beforeAll(async ({ request }) => {
    // Check if default pipeline already exists
    const listRes = await request.get(`${API_URL}/v1/crm/pipelines`, {
      headers: authHeaders(adminTokens),
    });
    const pipelines = await listRes.json();
    const hasDefault =
      Array.isArray(pipelines) && pipelines.some((p: Record<string, unknown>) => p.isDefault);

    if (!hasDefault) {
      // Create default pipeline
      const pipelineRes = await request.post(`${API_URL}/v1/crm/pipelines`, {
        headers: authHeaders(adminTokens),
        data: { name: 'E2E Default Pipeline', isDefault: true },
      });
      const pipeline = await pipelineRes.json();

      // Create stages: OPEN (default), WON, LOST
      await request.post(`${API_URL}/v1/crm/pipelines/${pipeline.id}/stages`, {
        headers: authHeaders(adminTokens),
        data: { name: 'Новый лид', position: 1, color: '#3B82F6', type: 'OPEN', isDefault: true },
      });
      await request.post(`${API_URL}/v1/crm/pipelines/${pipeline.id}/stages`, {
        headers: authHeaders(adminTokens),
        data: { name: 'Выиграна', position: 2, color: '#22C55E', type: 'WON' },
      });
      await request.post(`${API_URL}/v1/crm/pipelines/${pipeline.id}/stages`, {
        headers: authHeaders(adminTokens),
        data: { name: 'Проиграна', position: 3, color: '#6B7280', type: 'LOST' },
      });
    }
  });

  // -----------------------------------------------------------------------
  // Pipelines
  // -----------------------------------------------------------------------

  test.describe('Pipelines', () => {
    test('GET /v1/crm/pipelines — returns list for super_admin', async ({ request }) => {
      const response = await request.get(`${API_URL}/v1/crm/pipelines`, {
        headers: authHeaders(adminTokens),
      });

      expect(response.ok()).toBeTruthy();
      const body = await response.json();
      expect(Array.isArray(body)).toBe(true);
      expect(body.length).toBeGreaterThan(0);
    });

    test('POST /v1/crm/pipelines — creates pipeline', async ({ request }) => {
      const response = await request.post(`${API_URL}/v1/crm/pipelines`, {
        headers: authHeaders(adminTokens),
        data: { name: 'E2E Test Pipeline' },
      });

      expect(response.ok()).toBeTruthy();
      const body = await response.json();
      expect(body.name).toBe('E2E Test Pipeline');
      expect(body.id).toBeDefined();
    });
  });

  // -----------------------------------------------------------------------
  // Deals CRUD
  // -----------------------------------------------------------------------

  test.describe('Deals', () => {
    let dealId: string;

    test('POST /v1/crm/deals — creates deal', async ({ request }) => {
      const response = await request.post(`${API_URL}/v1/crm/deals`, {
        headers: authHeaders(adminTokens),
        data: {
          title: 'E2E Test Deal',
          contactName: 'Тест Тестов',
          contactPhone: '+79991234567',
          source: 'MANUAL',
        },
      });

      expect(response.ok()).toBeTruthy();
      const body = await response.json();
      expect(body.title).toBe('E2E Test Deal');
      expect(body.contactName).toBe('Тест Тестов');
      expect(body.id).toBeDefined();
      dealId = body.id;
    });

    test('GET /v1/crm/deals — lists deals', async ({ request }) => {
      const response = await request.get(`${API_URL}/v1/crm/deals`, {
        headers: authHeaders(adminTokens),
      });

      expect(response.ok()).toBeTruthy();
      const body = await response.json();
      expect(body.data).toBeDefined();
      expect(Array.isArray(body.data)).toBe(true);
    });

    test('GET /v1/crm/deals/:id — gets deal by ID', async ({ request }) => {
      if (!dealId) return;

      const response = await request.get(`${API_URL}/v1/crm/deals/${dealId}`, {
        headers: authHeaders(adminTokens),
      });

      expect(response.ok()).toBeTruthy();
      const body = await response.json();
      expect(body.id).toBe(dealId);
      expect(body.pipeline).toBeDefined();
      expect(body.stage).toBeDefined();
    });

    test('PATCH /v1/crm/deals/:id — updates deal', async ({ request }) => {
      if (!dealId) return;

      const response = await request.patch(`${API_URL}/v1/crm/deals/${dealId}`, {
        headers: authHeaders(adminTokens),
        data: { contactEmail: 'test@example.com' },
      });

      expect(response.ok()).toBeTruthy();
      const body = await response.json();
      expect(body.contactEmail).toBe('test@example.com');
    });

    test('POST /v1/crm/deals/:id/win — marks deal as won', async ({ request }) => {
      if (!dealId) return;

      const response = await request.post(`${API_URL}/v1/crm/deals/${dealId}/win`, {
        headers: authHeaders(adminTokens),
      });

      expect(response.ok()).toBeTruthy();
      const body = await response.json();
      expect(body.closedAt).toBeDefined();
    });
  });

  // -----------------------------------------------------------------------
  // Timeline
  // -----------------------------------------------------------------------

  test.describe('Timeline', () => {
    test('GET /v1/crm/deals/:id/timeline — returns timeline entries', async ({ request }) => {
      // Create a deal first
      const dealRes = await request.post(`${API_URL}/v1/crm/deals`, {
        headers: authHeaders(adminTokens),
        data: { title: 'Timeline Test Deal', contactName: 'Timeline Test', source: 'MANUAL' },
      });
      const deal = await dealRes.json();

      const response = await request.get(`${API_URL}/v1/crm/deals/${deal.id}/timeline`, {
        headers: authHeaders(adminTokens),
      });

      expect(response.ok()).toBeTruthy();
      const body = await response.json();
      expect(body.data).toBeDefined();
      expect(Array.isArray(body.data)).toBe(true);
      // Should have at least a system entry from deal creation
      expect(body.data.length).toBeGreaterThan(0);
    });

    test('POST /v1/crm/deals/:id/timeline/comment — adds comment', async ({ request }) => {
      const dealRes = await request.post(`${API_URL}/v1/crm/deals`, {
        headers: authHeaders(adminTokens),
        data: { title: 'Comment Test Deal', contactName: 'Comment Test', source: 'MANUAL' },
      });
      const deal = await dealRes.json();

      const response = await request.post(`${API_URL}/v1/crm/deals/${deal.id}/timeline/comment`, {
        headers: authHeaders(adminTokens),
        data: { content: 'E2E test comment' },
      });

      expect(response.status()).toBe(201);
      const body = await response.json();
      expect(body.type).toBe('COMMENT');
      expect(body.content).toBe('E2E test comment');
    });
  });

  // -----------------------------------------------------------------------
  // Activities
  // -----------------------------------------------------------------------

  test.describe('Activities', () => {
    test('POST /v1/crm/activities — creates activity', async ({ request }) => {
      const dealRes = await request.post(`${API_URL}/v1/crm/deals`, {
        headers: authHeaders(adminTokens),
        data: { title: 'Activity Test Deal', contactName: 'Activity Test', source: 'MANUAL' },
      });
      const deal = await dealRes.json();

      const response = await request.post(`${API_URL}/v1/crm/activities`, {
        headers: authHeaders(adminTokens),
        data: {
          dealId: deal.id,
          type: 'CALL',
          subject: 'Позвонить клиенту',
          scheduledAt: new Date(Date.now() + 86400000).toISOString(),
        },
      });

      expect(response.ok()).toBeTruthy();
      const body = await response.json();
      expect(body.subject).toBe('Позвонить клиенту');
      expect(body.type).toBe('CALL');
    });

    test('POST /v1/crm/activities/:id/complete — completes activity', async ({ request }) => {
      const dealRes = await request.post(`${API_URL}/v1/crm/deals`, {
        headers: authHeaders(adminTokens),
        data: { title: 'Complete Activity Test', contactName: 'Complete Test', source: 'MANUAL' },
      });
      const deal = await dealRes.json();

      const activityRes = await request.post(`${API_URL}/v1/crm/activities`, {
        headers: authHeaders(adminTokens),
        data: {
          dealId: deal.id,
          type: 'CALL',
          subject: 'Complete me',
          scheduledAt: new Date().toISOString(),
        },
      });
      const activity = await activityRes.json();

      const response = await request.post(`${API_URL}/v1/crm/activities/${activity.id}/complete`, {
        headers: authHeaders(adminTokens),
        data: { result: 'Клиент заинтересован' },
      });

      expect(response.ok()).toBeTruthy();
      const body = await response.json();
      expect(body.completedAt).toBeDefined();
      expect(body.result).toBe('Клиент заинтересован');
    });
  });

  // -----------------------------------------------------------------------
  // Form submission (public)
  // -----------------------------------------------------------------------

  test.describe('Form Submission', () => {
    test('POST /v1/crm/deals/from-form — creates deal from landing', async ({ request }) => {
      const response = await request.post(`${API_URL}/v1/crm/deals/from-form`, {
        data: {
          name: 'Иван Тестов',
          phone: '+79991234567',
          email: 'ivan@test.com',
          source: 'landing',
          formFilledMs: 5000,
        },
      });

      expect(response.ok()).toBeTruthy();
      const body = await response.json();
      expect(body.success).toBe(true);
      expect(body.dealId).toBeDefined();
    });

    test('POST /v1/crm/deals/from-form — blocks honeypot', async ({ request }) => {
      const response = await request.post(`${API_URL}/v1/crm/deals/from-form`, {
        data: {
          name: 'Bot',
          phone: '+79991234567',
          honeypot: 'I am a bot',
          formFilledMs: 100,
        },
      });

      expect(response.ok()).toBeTruthy();
      const body = await response.json();
      expect(body.success).toBe(false);
      expect(body.error).toBe('spam');
    });
  });

  // -----------------------------------------------------------------------
  // RBAC
  // -----------------------------------------------------------------------

  test.describe('RBAC', () => {
    test('Trainer cannot create deals', async ({ request }) => {
      const response = await request.post(`${API_URL}/v1/crm/deals`, {
        headers: authHeaders(trainerTokens),
        data: { title: 'Should Fail', source: 'MANUAL' },
      });

      expect(response.status()).toBe(403);
    });

    test('Trainer cannot create pipelines', async ({ request }) => {
      const response = await request.post(`${API_URL}/v1/crm/pipelines`, {
        headers: authHeaders(trainerTokens),
        data: { name: 'Should Fail' },
      });

      expect(response.status()).toBe(403);
    });
  });

  // -----------------------------------------------------------------------
  // Lost Reasons
  // -----------------------------------------------------------------------

  test.describe('Lost Reasons', () => {
    test('CRUD for lost reasons', async ({ request }) => {
      // Create
      const createRes = await request.post(`${API_URL}/v1/crm/lost-reasons`, {
        headers: authHeaders(adminTokens),
        data: { name: 'Слишком дорого' },
      });
      expect(createRes.ok()).toBeTruthy();
      const reason = await createRes.json();
      expect(reason.name).toBe('Слишком дорого');

      // List
      const listRes = await request.get(`${API_URL}/v1/crm/lost-reasons`, {
        headers: authHeaders(adminTokens),
      });
      expect(listRes.ok()).toBeTruthy();
      const list = await listRes.json();
      expect(Array.isArray(list)).toBe(true);
      expect(list.some((r: Record<string, unknown>) => r.id === reason.id)).toBe(true);

      // Update
      const updateRes = await request.patch(`${API_URL}/v1/crm/lost-reasons/${reason.id}`, {
        headers: authHeaders(adminTokens),
        data: { name: 'Цена выше бюджета' },
      });
      expect(updateRes.ok()).toBeTruthy();
      const updated = await updateRes.json();
      expect(updated.name).toBe('Цена выше бюджета');
    });
  });

  // -----------------------------------------------------------------------
  // Custom Fields
  // -----------------------------------------------------------------------

  test.describe('Custom Fields', () => {
    test('CRUD for custom fields', async ({ request }) => {
      // Create
      const createRes = await request.post(`${API_URL}/v1/crm/fields`, {
        headers: authHeaders(adminTokens),
        data: {
          entityType: 'deal',
          name: 'Размер обуви',
          fieldName: 'shoe_size',
          type: 'INTEGER',
        },
      });
      expect(createRes.ok()).toBeTruthy();
      const field = await createRes.json();
      expect(field.name).toBe('Размер обуви');
      expect(field.fieldName).toBe('shoe_size');

      // List
      const listRes = await request.get(`${API_URL}/v1/crm/fields?entityType=deal`, {
        headers: authHeaders(adminTokens),
      });
      expect(listRes.ok()).toBeTruthy();
      const fields = await listRes.json();
      expect(Array.isArray(fields)).toBe(true);

      // Update
      const updateRes = await request.patch(`${API_URL}/v1/crm/fields/${field.id}`, {
        headers: authHeaders(adminTokens),
        data: { name: 'Размер ноги' },
      });
      expect(updateRes.ok()).toBeTruthy();
      const updated = await updateRes.json();
      expect(updated.name).toBe('Размер ноги');
    });
  });
});
