import { describe, it, expect, beforeEach, afterEach, beforeAll } from 'vitest';
import { 
  setupE2ETestEnvironment, 
  E2ETestEnvironment 
} from '../utils/e2eTestSetup';
import { 
  createTestTicket,
  createTestTickets,
  createTestTicketSet,
  createTicketsForPagination,
  createTestTicketComment,
  createTicketTestData,
  createTicketCommentTestData
} from '../utils/ticketTestData';
import { 
  assertSuccess, 
  assertError, 
  buildQueryString,
  extractPagination
} from '../utils/apiTestHelpers';
import { v4 as uuidv4 } from 'uuid';

describe('Ticket API E2E Tests', () => {
  let env: E2ETestEnvironment;
  const API_BASE = '/api/v1/tickets';
  let statusIds: { open: string; inProgress: string; closed: string };
  let priorityIds: { low: string; medium: string; high: string };
  let boardId: string;

  beforeAll(async () => {
    env = await setupE2ETestEnvironment();

    // Set up test data - create necessary entities
    const db = env.db;
    
    // Get the default board created by setupE2ETestEnvironment
    const existingBoard = await db('boards')
      .where({ tenant: env.tenant, is_default: true })
      .first();
    
    if (existingBoard) {
      boardId = existingBoard.board_id;
    } else {
      // Create a test board if none exists
      boardId = uuidv4();
      await db('boards').insert({
        board_id: boardId,
        board_name: 'Test Board',
        tenant: env.tenant,
        display_order: 99
      });
    }

    // Get existing statuses created by setupE2ETestEnvironment
    const newStatus = await db('statuses')
      .where({ tenant: env.tenant, board_id: boardId, name: 'New', status_type: 'ticket' })
      .first();
    const inProgressStatus = await db('statuses')
      .where({ tenant: env.tenant, board_id: boardId, name: 'In Progress', status_type: 'ticket' })
      .first();
    const closedStatus = await db('statuses')
      .where({ tenant: env.tenant, board_id: boardId, name: 'Closed', status_type: 'ticket' })
      .first();

    statusIds = {
      open: newStatus?.status_id || uuidv4(),
      inProgress: inProgressStatus?.status_id || uuidv4(),
      closed: closedStatus?.status_id || uuidv4()
    };

    // Get existing priorities created by setupE2ETestEnvironment
    const lowPriority = await db('priorities')
      .where({ tenant: env.tenant, priority_name: 'Low' })
      .first();
    const mediumPriority = await db('priorities')
      .where({ tenant: env.tenant, priority_name: 'Medium' })
      .first();
    const highPriority = await db('priorities')
      .where({ tenant: env.tenant, priority_name: 'High' })
      .first();

    priorityIds = {
      low: lowPriority?.priority_id || uuidv4(),
      medium: mediumPriority?.priority_id || uuidv4(),
      high: highPriority?.priority_id || uuidv4()
    };
    
    // Priorities should already be created by setupE2ETestEnvironment
  });

  afterAll(async () => {
    if (env) {
      // Clean up any remaining test data - delete in order to respect foreign keys
      await env.db('comments').where('tenant', env.tenant).delete();
      await env.db('tickets').where('tenant', env.tenant).delete();
      await env.cleanup();
    }
  });

  describe('Authentication', () => {
    it('should require API key for all endpoints', async () => {
      // Remove API key for this test
      const { ApiTestClient } = await import('../utils/apiTestHelpers');
      const clientWithoutKey = new ApiTestClient({
        baseUrl: env.apiClient['config'].baseUrl
      });

      const response = await clientWithoutKey.get(API_BASE);
      assertError(response, 401, 'UNAUTHORIZED');
      expect(response.data.error.message).toContain('API key required');
    });

    it('should reject invalid API key', async () => {
      const { ApiTestClient } = await import('../utils/apiTestHelpers');
      const clientWithBadKey = new ApiTestClient({
        baseUrl: env.apiClient['config'].baseUrl,
        apiKey: 'invalid-api-key-12345'
      });

      const response = await clientWithBadKey.get(API_BASE);
      assertError(response, 401, 'UNAUTHORIZED');
      expect(response.data.error.message).toContain('Invalid API key');
    });
  });

  describe('CRUD Operations', () => {
    describe('Create Ticket (POST /api/v1/tickets)', () => {
      it('should create a new ticket', async () => {
        const newTicket = createTicketTestData({
          client_id: env.clientId,
          board_id: boardId,
          status_id: statusIds.open,
          priority_id: priorityIds.medium
        });

        const response = await env.apiClient.post(API_BASE, newTicket);
        assertSuccess(response, 201);
        
        expect(response.data.data).toMatchObject({
          title: newTicket.title,
          client_id: env.clientId,
          status_id: statusIds.open,
          priority_id: priorityIds.medium,
          tenant: env.tenant
        });
        expect(response.data.data.ticket_id).toBeDefined();
        expect(response.data.data.ticket_number).toBeDefined();
      });

      it('should validate required fields', async () => {
        const invalidTicket = {
          description: 'Missing title'
          // Missing required title
        };

        const response = await env.apiClient.post(API_BASE, invalidTicket);
        assertError(response, 400, 'VALIDATION_ERROR');
      });

      it('should create ticket with all optional fields', async () => {
        // First create a contact for the ticket
        const contactId = uuidv4();
        await env.db('contacts').insert({
          contact_name_id: contactId,
          tenant: env.tenant,
          client_id: env.clientId,
          full_name: 'Test Contact',
          email: 'test.contact@example.com',
          created_at: new Date().toISOString()
        });

        const tomorrow = new Date(Date.now() + 24 * 60 * 60 * 1000);
        const fullTicket = createTicketTestData({
          client_id: env.clientId,
          board_id: boardId,
          contact_name_id: contactId,
          status_id: statusIds.open,
          priority_id: priorityIds.high,
          assigned_to: env.userId,
          attributes: { 
            description: 'Detailed ticket description',
            due_date: tomorrow.toISOString(),
            scheduled_start: tomorrow.toISOString(),
            scheduled_end: new Date(tomorrow.getTime() + 2 * 60 * 60 * 1000).toISOString(),
            department: 'IT', 
            location: 'Building A' 
          },
          tags: ['urgent', 'customer-request']
        });

        const response = await env.apiClient.post(API_BASE, fullTicket);
        assertSuccess(response, 201);
        
        expect(response.data.data.tags).toEqual(expect.arrayContaining(['urgent', 'customer-request']));
        expect(response.data.data.attributes).toMatchObject(fullTicket.attributes);
      });
    });

    describe('Get Ticket (GET /api/v1/tickets/:id)', () => {
      it('should retrieve a ticket by ID', async () => {
        // Create a test ticket
        const ticket = await createTestTicket(env.db, env.tenant, {
          title: 'Test Ticket for Retrieval',
          description: 'This ticket will be retrieved',
          client_id: env.clientId,
          board_id: boardId,
          status_id: statusIds.open,
          priority_id: priorityIds.low
        });

        const response = await env.apiClient.get(`${API_BASE}/${ticket.ticket_id}`);
        assertSuccess(response);
        
        expect(response.data.data).toMatchObject({
          ticket_id: ticket.ticket_id,
          title: ticket.title,
          client_id: ticket.client_id
        });
        
        // Check description in attributes
        expect(response.data.data.attributes?.description).toBe('This ticket will be retrieved');
      });

      it('should return 404 for non-existent ticket', async () => {
        const fakeId = '00000000-0000-0000-0000-000000000000';
        const response = await env.apiClient.get(`${API_BASE}/${fakeId}`);
        assertError(response, 404, 'NOT_FOUND');
      });

      it('should not return tickets from other tenants', async () => {
        // This test would require creating another tenant and ticket
        // For now, we'll skip this test as it requires more complex setup
      });
    });

    describe('Update Ticket (PUT /api/v1/tickets/:id)', () => {
      it('should update a ticket', async () => {
        const ticket = await createTestTicket(env.db, env.tenant, {
          title: 'Original Title',
          description: 'Original description',
          board_id: boardId,
          status_id: statusIds.open,
          priority_id: priorityIds.low
        });

        const updates = {
          title: 'Updated Title',
          attributes: {
            description: 'Updated description'
          },
          status_id: statusIds.inProgress,
          priority_id: priorityIds.high
        };

        const response = await env.apiClient.put(`${API_BASE}/${ticket.ticket_id}`, updates);
        assertSuccess(response);
        
        expect(response.data.data).toMatchObject({
          ticket_id: ticket.ticket_id,
          title: updates.title,
          status_id: updates.status_id,
          priority_id: updates.priority_id
        });
        
        // Check description in attributes
        expect(response.data.data.attributes?.description).toBe('Updated description');
      });

      it('persists serialized rich-text descriptions and returns render-friendly HTML on refetch', async () => {
        const ticket = await createTestTicket(env.db, env.tenant, {
          title: 'Rich mobile description',
          description: 'Legacy plain description',
          board_id: boardId,
          status_id: statusIds.open,
          priority_id: priorityIds.medium
        });

        const richDescription = JSON.stringify({
          type: 'doc',
          content: [
            {
              type: 'paragraph',
              content: [{ type: 'text', text: 'Updated rich description' }]
            }
          ]
        });

        const updateResponse = await env.apiClient.put(`${API_BASE}/${ticket.ticket_id}`, {
          attributes: {
            description: richDescription
          }
        });
        assertSuccess(updateResponse);
        expect(updateResponse.data.data.attributes?.description).toBe(richDescription);

        const refetchResponse = await env.apiClient.get(`${API_BASE}/${ticket.ticket_id}`);
        assertSuccess(refetchResponse);
        expect(refetchResponse.data.data.attributes?.description).toBe(richDescription);
        expect(refetchResponse.data.data.description_html).toContain('Updated rich description');
      });

      it('should return 404 when updating non-existent ticket', async () => {
        const fakeId = '00000000-0000-0000-0000-000000000000';
        const response = await env.apiClient.put(`${API_BASE}/${fakeId}`, { title: 'New Title' });
        assertError(response, 404, 'NOT_FOUND');
      });

      it('should validate update data', async () => {
        const ticket = await createTestTicket(env.db, env.tenant, {
          board_id: boardId,
          status_id: statusIds.open,
          priority_id: priorityIds.medium
        });
        
        const invalidUpdate = {
          title: '' // Empty title should be invalid
        };

        const response = await env.apiClient.put(`${API_BASE}/${ticket.ticket_id}`, invalidUpdate);
        assertError(response, 400, 'VALIDATION_ERROR');
      });
    });

    describe('Delete Ticket (DELETE /api/v1/tickets/:id)', () => {
      it('should delete a ticket', async () => {
        const ticket = await createTestTicket(env.db, env.tenant, {
          title: 'To Delete',
          description: 'This ticket will be deleted',
          board_id: boardId,
          status_id: statusIds.open,
          priority_id: priorityIds.low
        });

        const response = await env.apiClient.delete(`${API_BASE}/${ticket.ticket_id}`);
        assertSuccess(response, 204);

        // Verify ticket is deleted
        const getResponse = await env.apiClient.get(`${API_BASE}/${ticket.ticket_id}`);
        assertError(getResponse, 404);
      });

      it('should return 404 when deleting non-existent ticket', async () => {
        const fakeId = '00000000-0000-0000-0000-000000000000';
        const response = await env.apiClient.delete(`${API_BASE}/${fakeId}`);
        assertError(response, 404, 'NOT_FOUND');
      });
    });
  });

  describe('List Tickets (GET /api/v1/tickets)', () => {
    // Test data will be created as needed in individual tests

    it('should list all tickets with default pagination', async () => {
      const response = await env.apiClient.get(API_BASE);
      assertSuccess(response);

      expect(response.data.data).toBeInstanceOf(Array);
      expect(response.data.pagination).toBeDefined();
      expect(response.data.pagination).toMatchObject({
        page: 1,
        limit: 25,
        total: expect.any(Number),
        totalPages: expect.any(Number),
        hasNext: expect.any(Boolean),
        hasPrev: false
      });
    });

    it('should support pagination parameters', async () => {
      await createTicketsForPagination(env.db, env.tenant, env.clientId, boardId, 15);

      const query = buildQueryString({ page: 2, limit: 5 });
      const response = await env.apiClient.get(`${API_BASE}${query}`);
      assertSuccess(response);

      const pagination = extractPagination(response);
      expect(pagination.page).toBe(2);
      expect(pagination.limit).toBe(5);
      expect(pagination.hasPrev).toBe(true);
    });

    it('should filter by client_id', async () => {
      const query = buildQueryString({ client_id: env.clientId });
      const response = await env.apiClient.get(`${API_BASE}${query}`);
      assertSuccess(response);

      response.data.data.forEach((ticket: any) => {
        expect(ticket.client_id).toBe(env.clientId);
      });
    });

    it('should filter by status', async () => {
      const query = buildQueryString({ status_id: statusIds.open });
      const response = await env.apiClient.get(`${API_BASE}${query}`);
      assertSuccess(response);

      response.data.data.forEach((ticket: any) => {
        expect(ticket.status_id).toBe(statusIds.open);
      });
    });

    it('should filter by priority', async () => {
      const query = buildQueryString({ priority_id: priorityIds.high });
      const response = await env.apiClient.get(`${API_BASE}${query}`);
      assertSuccess(response);

      response.data.data.forEach((ticket: any) => {
        expect(ticket.priority_id).toBe(priorityIds.high);
      });
    });

    it('should filter by assigned user', async () => {
      // Create ticket assigned to specific user
      await createTestTicket(env.db, env.tenant, {
        title: 'Assigned Ticket',
        board_id: boardId,
        status_id: statusIds.open,
        priority_id: priorityIds.medium,
        assigned_to: env.userId
      });

      const query = buildQueryString({ assigned_to: env.userId });
      const response = await env.apiClient.get(`${API_BASE}${query}`);
      assertSuccess(response);

      const assignedTickets = response.data.data.filter((t: any) => t.assigned_to === env.userId);
      expect(assignedTickets.length).toBeGreaterThan(0);
    });

    it('should filter overdue tickets', async () => {
      const query = buildQueryString({ is_overdue: 'true' });
      const response = await env.apiClient.get(`${API_BASE}${query}`);
      assertSuccess(response);

      // May return tickets with is_overdue flag or check attributes
      expect(response.data.data).toBeInstanceOf(Array);
    });

    it('should sort tickets by created date', async () => {
      const query = buildQueryString({ sort: 'entered_at', order: 'desc' });
      const response = await env.apiClient.get(`${API_BASE}${query}`);
      assertSuccess(response);

      const dates = response.data.data.map((t: any) => new Date(t.entered_at).getTime());
      const sortedDates = [...dates].sort((a, b) => b - a);
      expect(dates).toEqual(sortedDates);
    });
  });

  describe('Search Tickets (GET /api/v1/tickets/search)', () => {
    let searchableTickets: any[] = [];

    beforeEach(async () => {
      // Create test tickets with searchable content in title
      searchableTickets = [];
      
      const ticket1 = await createTestTicket(env.db, env.tenant, {
        title: 'Important ticket for search test',
        client_id: env.clientId,
        board_id: boardId,
        entered_by: env.userId,
        status_id: statusIds.open,
        priority_id: priorityIds.medium
      });
      searchableTickets.push(ticket1);
      
      const ticket2 = await createTestTicket(env.db, env.tenant, {
        title: 'Another ticket to find',
        client_id: env.clientId,
        board_id: boardId,
        entered_by: env.userId,
        status_id: statusIds.open,
        priority_id: priorityIds.high
      });
      searchableTickets.push(ticket2);
      
      const ticket3 = await createTestTicket(env.db, env.tenant, {
        title: 'Special ticket case',
        client_id: env.clientId,
        board_id: boardId,
        entered_by: env.userId,
        status_id: statusIds.open,
        priority_id: priorityIds.low
      });
      searchableTickets.push(ticket3);
    });

    afterEach(async () => {
      // Clean up created tickets
      for (const ticket of searchableTickets) {
        await env.db('tickets').where('ticket_id', ticket.ticket_id).delete();
      }
    });

    it('should search tickets by query', async () => {
      // Search for the word "ticket" which appears in all our test titles
      const query = buildQueryString({ 
        query: 'ticket'
      });
      const response = await env.apiClient.get(`${API_BASE}/search${query}`);
      assertSuccess(response);

      expect(response.data.data.length).toBeGreaterThanOrEqual(3);
      response.data.data.forEach((ticket: any) => {
        const hasTicket = 
          ticket.title.toLowerCase().includes('ticket') ||
          ticket.ticket_number?.toLowerCase().includes('ticket');
        expect(hasTicket).toBe(true);
      });
    });

    it('should search in specified fields', async () => {
      // Create a ticket with unique content in the title
      const uniqueTicket = await createTestTicket(env.db, env.tenant, {
        title: 'UniqueTitle123',
        client_id: env.clientId,
        board_id: boardId,
        entered_by: env.userId,
        status_id: statusIds.open,
        priority_id: priorityIds.medium
      });
      searchableTickets.push(uniqueTicket);
      
      const query = buildQueryString({ 
        query: 'UniqueTitle123',
        fields: JSON.stringify(['title'])
      });
      const response = await env.apiClient.get(`${API_BASE}/search${query}`);
      assertSuccess(response);

      expect(response.data.data.length).toBe(1);
      expect(response.data.data[0].title).toBe('UniqueTitle123');
    });

    it('should limit search results', async () => {
      const query = buildQueryString({ query: 'e', limit: '2' });
      const response = await env.apiClient.get(`${API_BASE}/search${query}`);
      assertSuccess(response);

      expect(response.data.data.length).toBeLessThanOrEqual(2);
    });
  });

  describe('Ticket Comments (POST /api/v1/tickets/:id/comments)', () => {
    let testTicket: any;

    beforeEach(async () => {
      testTicket = await createTestTicket(env.db, env.tenant, {
        title: 'Ticket for Comments',
        client_id: env.clientId,
        board_id: boardId,
        status_id: statusIds.open,
        priority_id: priorityIds.medium
      });
    });

    it('should add a comment to a ticket', async () => {
      const commentData = createTicketCommentTestData();

      const response = await env.apiClient.post(
        `${API_BASE}/${testTicket.ticket_id}/comments`,
        commentData
      );
      assertSuccess(response, 201);

      expect(response.data.data).toMatchObject({
        ticket_id: testTicket.ticket_id,
        comment_text: commentData.comment_text,
        is_internal: commentData.is_internal
      });
    });

    it('persists serialized rich-text comments and returns render-friendly HTML on refetch', async () => {
      const richComment = JSON.stringify({
        type: 'doc',
        content: [
          {
            type: 'paragraph',
            content: [{ type: 'text', text: 'Rich mobile comment' }]
          }
        ]
      });

      const createResponse = await env.apiClient.post(
        `${API_BASE}/${testTicket.ticket_id}/comments`,
        {
          comment_text: richComment,
          is_internal: true
        }
      );
      assertSuccess(createResponse, 201);
      expect(createResponse.data.data.comment_text).toBe(richComment);

      const listResponse = await env.apiClient.get(`${API_BASE}/${testTicket.ticket_id}/comments`);
      assertSuccess(listResponse);

      expect(listResponse.data.data).toEqual(
        expect.arrayContaining([
          expect.objectContaining({
            comment_text: richComment,
            comment_html: expect.stringContaining('Rich mobile comment')
          })
        ])
      );
    });

    it('should add an internal comment', async () => {
      const commentData = createTicketCommentTestData({
        comment: 'Internal note: Check with senior tech',
        is_internal: true
      });

      const response = await env.apiClient.post(
        `${API_BASE}/${testTicket.ticket_id}/comments`,
        commentData
      );
      assertSuccess(response, 201);

      expect(response.data.data.is_internal).toBe(true);
    });

    it('should reject overly long comments', async () => {
      const longComment = 'a'.repeat(5001);
      const response = await env.apiClient.post(
        `${API_BASE}/${testTicket.ticket_id}/comments`,
        { comment_text: longComment, is_internal: true }
      );
      assertError(response, 400, 'VALIDATION_ERROR');
      expect(response.data.error.message.toLowerCase()).toContain('too long');
    });

    it('should list ticket comments', async () => {
      // Create multiple comments
      await createTestTicketComment(env.db, env.tenant, testTicket.ticket_id, env.userId, {
        comment_text: 'First comment'
      });
      await createTestTicketComment(env.db, env.tenant, testTicket.ticket_id, env.userId, {
        comment_text: 'Second comment',
        is_internal: true
      });

      const response = await env.apiClient.get(`${API_BASE}/${testTicket.ticket_id}/comments`);
      assertSuccess(response);

      expect(response.data.data).toBeInstanceOf(Array);
      expect(response.data.data.length).toBeGreaterThanOrEqual(2);
    });

    it('should return 404 when adding comment to non-existent ticket', async () => {
      const fakeId = '00000000-0000-0000-0000-000000000000';
      const response = await env.apiClient.post(
        `${API_BASE}/${fakeId}/comments`,
        { comment_text: 'Test' }
      );
      assertError(response, 404, 'NOT_FOUND');
    });
  });

  describe('Ticket Status Updates (PUT /api/v1/tickets/:id/status)', () => {
    let testTicket: any;

    beforeEach(async () => {
      testTicket = await createTestTicket(env.db, env.tenant, {
        title: 'Ticket for Status Updates',
        board_id: boardId,
        status_id: statusIds.open,
        priority_id: priorityIds.medium
      });
    });

    it('should update ticket status', async () => {
      const statusUpdate = {
        status_id: statusIds.inProgress,
        reason: 'Starting work on this ticket'
      };

      const response = await env.apiClient.put(
        `${API_BASE}/${testTicket.ticket_id}/status`,
        statusUpdate
      );
      assertSuccess(response);

      expect(response.data.data.status_id).toBe(statusIds.inProgress);
      // Optionally check if status history was created
    });

    it('should validate status transitions', async () => {
      // This test assumes there are business rules for status transitions
      // For example, can't go directly from 'open' to 'closed' without 'in_progress'
      // Adjust based on actual business rules
    });
  });

  describe('Ticket Assignment (PUT /api/v1/tickets/:id/assignment)', () => {
    let testTicket: any;

    beforeEach(async () => {
      testTicket = await createTestTicket(env.db, env.tenant, {
        title: 'Ticket for Assignment',
        client_id: env.clientId,
        board_id: boardId,
        status_id: statusIds.open,
        priority_id: priorityIds.medium
      });
    });

    it('should assign ticket to user', async () => {
      const assignment = {
        assigned_to: env.userId,
        notes: 'Assigning to primary technician'
      };

      const response = await env.apiClient.put(
        `${API_BASE}/${testTicket.ticket_id}/assignment`,
        assignment
      );
      assertSuccess(response);

      expect(response.data.data.assigned_to).toBe(env.userId);
    });

    it('should unassign ticket', async () => {
      // First assign
      await env.apiClient.put(
        `${API_BASE}/${testTicket.ticket_id}/assignment`,
        { assigned_to: env.userId }
      );

      // Then unassign
      const response = await env.apiClient.put(
        `${API_BASE}/${testTicket.ticket_id}/assignment`,
        { assigned_to: null }
      );
      assertSuccess(response);

      expect(response.data.data.assigned_to).toBeNull();
    });
  });

  describe('Ticket Statistics (GET /api/v1/tickets/stats)', () => {
    // Test data will be created as needed in individual tests

    it('should return ticket statistics', async () => {
      const response = await env.apiClient.get(`${API_BASE}/stats`);
      assertSuccess(response);

      expect(response.data.data).toMatchObject({
        total_tickets: expect.any(Number),
        open_tickets: expect.any(Number),
        closed_tickets: expect.any(Number),
        overdue_tickets: expect.any(Number),
        tickets_by_status: expect.any(Object),
        tickets_by_priority: expect.any(Object),
        average_resolution_time: null, // Not implemented yet
        tickets_created_today: expect.any(Number),
        tickets_created_this_week: expect.any(Number),
        tickets_created_this_month: expect.any(Number)
      });
    });

    it('should filter statistics by date range', async () => {
      const startDate = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000); // 7 days ago
      const endDate = new Date();
      
      const query = buildQueryString({ 
        start_date: startDate.toISOString(),
        end_date: endDate.toISOString()
      });
      const response = await env.apiClient.get(`${API_BASE}/stats${query}`);
      assertSuccess(response);

      expect(response.data.data).toBeDefined();
    });

    it('should filter statistics by client', async () => {
      const query = buildQueryString({ client_id: env.clientId });
      const response = await env.apiClient.get(`${API_BASE}/stats${query}`);
      assertSuccess(response);

      expect(response.data.data).toBeDefined();
    });
  });

  describe('Create Ticket from Asset (POST /api/v1/tickets/from-asset)', () => {
    it('should create ticket from asset', async () => {
      const assetId = uuidv4(); // In real test, this would be a real asset ID

      const ticketData = {
        asset_id: assetId,
        title: 'Issue with server',
        description: 'Server is not responding',
        priority_id: priorityIds.high,
        client_id: env.clientId
      };

      const response = await env.apiClient.post(`${API_BASE}/from-asset`, ticketData);
      
      // This might return 404 if asset doesn't exist
      if (response.status === 201) {
        assertSuccess(response, 201);
        expect(response.data.data.asset_id).toBe(assetId);
      } else {
        assertError(response, 404, 'NOT_FOUND');
      }
    });
  });

  describe('Error Handling', () => {
    it('should handle invalid UUID format', async () => {
      const response = await env.apiClient.get(`${API_BASE}/not-a-uuid`);
      assertError(response, 400, 'VALIDATION_ERROR');
    });

    it('should handle invalid query parameters', async () => {
      const query = buildQueryString({ page: 'invalid', limit: 'abc' });
      const response = await env.apiClient.get(`${API_BASE}${query}`);
      assertError(response, 400, 'VALIDATION_ERROR');
    });

    it('should handle missing required fields on create', async () => {
      const response = await env.apiClient.post(API_BASE, {});
      assertError(response, 400, 'VALIDATION_ERROR');
    });

    it('should handle invalid date formats', async () => {
      const invalidTicket = createTicketTestData({
        attributes: {
          due_date: 'not-a-date'
        }
      });

      const response = await env.apiClient.post(API_BASE, invalidTicket);
      // Attributes are flexible JSON, so this might not error
      // Just verify response status
      expect([200, 201, 400]).toContain(response.status);
    });
  });

  describe('Permissions', () => {
    it('should enforce read permissions for GET endpoints', async () => {
      // This would require creating a user without read permissions
      // For now, we'll skip this test as it requires RBAC setup
    });

    it('should enforce write permissions for POST/PUT/DELETE', async () => {
      // This would require creating a user without write permissions
      // For now, we'll skip this test as it requires RBAC setup
    });

    it('should enforce assignment permissions', async () => {
      // Test that only certain roles can assign tickets
      // Requires RBAC setup
    });
  });

  describe('Multi-tenancy', () => {
    it('should isolate tickets by tenant', async () => {
      // This would require creating another tenant and verifying isolation
      // For now, we'll skip this test as it requires complex setup
    });
  });

  describe('Advanced Features', () => {
    it('should support bulk operations', async () => {
      // Create multiple tickets
      const ticketIds = [];
      for (let i = 0; i < 3; i++) {
        const ticket = await createTestTicket(env.db, env.tenant, {
          title: `Bulk Update Test ${i}`,
          board_id: boardId,
          status_id: statusIds.open,
          priority_id: priorityIds.medium
        });
        ticketIds.push(ticket.ticket_id);
      }

      // Test bulk status update
      const bulkUpdate = {
        ticket_ids: ticketIds,
        updates: {
          status_id: statusIds.closed
        }
      };

      // This endpoint might not exist yet - adjust based on actual API
      const response = await env.apiClient.post(`${API_BASE}/bulk-update`, bulkUpdate);
      
      if (response.status === 404 || response.status === 405) {
        // Bulk update endpoint doesn't exist yet or method not allowed
        expect([404, 405]).toContain(response.status);
      } else {
        assertSuccess(response);
      }
    });

    it('should support ticket templates', async () => {
      // Test creating ticket from template
      const templateData = {
        template_id: 'incident-template',
        overrides: {
          title: 'Network Incident - Building A'
        }
      };

      // This endpoint might not exist yet
      const response = await env.apiClient.post(`${API_BASE}/from-template`, templateData);
      
      if (response.status === 404 || response.status === 405) {
        expect([404, 405]).toContain(response.status);
      } else {
        assertSuccess(response, 201);
      }
    });

    it('should track ticket history', async () => {
      const ticket = await createTestTicket(env.db, env.tenant, {
        title: 'History Test Ticket',
        board_id: boardId,
        status_id: statusIds.open,
        priority_id: priorityIds.medium
      });

      // Update ticket to generate history
      await env.apiClient.put(`${API_BASE}/${ticket.ticket_id}`, {
        title: 'Updated History Test Ticket'
      });

      // Get ticket history - endpoint might not exist
      const response = await env.apiClient.get(`${API_BASE}/${ticket.ticket_id}/history`);
      
      if (response.status === 404) {
        expect(response.status).toBe(404);
      } else {
        assertSuccess(response);
        expect(response.data.data).toBeInstanceOf(Array);
      }
    });
  });
});
