import { describe, it, expect, beforeEach } from 'vitest';

import {
  _setRegisteredGroupForTests,
  _initTestDatabase,
  storeMessage,
  storeChatMetadata,
  createProducedWorkItem,
  getOpenWorkItem,
  getLastBotFinalMessage,
  markWorkItemDelivered,
} from './db.js';
import { normalizeMessageForDedupe } from './router.js';
import { hasReviewerLease } from './service-routing.js';
import { isDuplicateOfLastBotFinal } from './message-runtime.js';

beforeEach(() => {
  _initTestDatabase();
});

// Helper to create a message
const createMessage = (
  overrides: Partial<{
    id: string;
    chat_jid: string;
    sender: string;
    sender_name: string;
    content: string;
    timestamp: string;
    is_from_me: boolean;
    is_bot_message: boolean;
  }> = {},
) => ({
  id: overrides.id ?? 'msg-1',
  chat_jid: overrides.chat_jid ?? 'dc:test-room',
  sender: overrides.sender ?? 'user1',
  sender_name: overrides.sender_name ?? 'User',
  content: overrides.content ?? 'Hello',
  timestamp: overrides.timestamp ?? new Date().toISOString(),
  is_from_me: overrides.is_from_me ?? false,
  is_bot_message: overrides.is_bot_message ?? false,
});

// Helper to setup chat metadata
const setupChat = (jid: string) => {
  storeChatMetadata(
    jid,
    new Date().toISOString(),
    'Test Chat',
    'discord',
    true,
  );
};

describe('hasReviewerLease', () => {
  it('returns true when both claude-code and codex are registered', () => {
    const jid = 'dc:paired-room';

    _setRegisteredGroupForTests(jid, {
      name: 'Paired Room',
      folder: 'paired-room',
      trigger: '@claude',
      added_at: new Date().toISOString(),
      agentType: 'claude-code',
    });

    _setRegisteredGroupForTests(jid, {
      name: 'Paired Room',
      folder: 'paired-room',
      trigger: '@codex',
      added_at: new Date().toISOString(),
      agentType: 'codex',
    });

    expect(hasReviewerLease(jid)).toBe(true);
  });

  it('returns false when only claude-code is registered', () => {
    const jid = 'dc:single-claude';

    _setRegisteredGroupForTests(jid, {
      name: 'Single Claude',
      folder: 'single-claude',
      trigger: '@claude',
      added_at: new Date().toISOString(),
      agentType: 'claude-code',
    });

    expect(hasReviewerLease(jid)).toBe(false);
  });

  it('returns false when only codex is registered', () => {
    const jid = 'dc:single-codex';

    _setRegisteredGroupForTests(jid, {
      name: 'Single Codex',
      folder: 'single-codex',
      trigger: '@codex',
      added_at: new Date().toISOString(),
      agentType: 'codex',
    });

    expect(hasReviewerLease(jid)).toBe(false);
  });
});

describe('getLastBotFinalMessage', () => {
  it('returns the most recent bot message from any service (is_bot_message=1)', () => {
    const jid = 'dc:test-room';
    const now = new Date();
    setupChat(jid);

    // Store older bot message (from any bot)
    storeMessage(
      createMessage({
        id: 'msg-1',
        chat_jid: jid,
        content: 'First bot message',
        timestamp: new Date(now.getTime() - 1000).toISOString(),
        is_from_me: true,
        is_bot_message: true,
      }),
    );

    // Store newer bot message (from different bot - is_from_me=0 but is_bot_message=1)
    storeMessage(
      createMessage({
        id: 'msg-2',
        chat_jid: jid,
        content: 'Second bot message',
        timestamp: now.toISOString(),
        is_from_me: false, // Different bot
        is_bot_message: true,
      }),
    );

    // Store human message (should not be returned)
    storeMessage(
      createMessage({
        id: 'msg-3',
        chat_jid: jid,
        content: 'Human message',
        timestamp: new Date(now.getTime() + 1000).toISOString(),
        is_from_me: false,
        is_bot_message: false,
      }),
    );

    const lastMessages = getLastBotFinalMessage(jid, 'claude-code', 1);
    expect(lastMessages).toHaveLength(1);
    expect(lastMessages[0].content).toBe('Second bot message');
  });

  it('returns empty array when no bot messages exist', () => {
    const jid = 'dc:empty-room';
    setupChat(jid);

    const lastMessages = getLastBotFinalMessage(jid, 'claude-code', 1);
    expect(lastMessages).toHaveLength(0);
  });
});

describe('normalizeMessageForDedupe', () => {
  it('normalizes messages for comparison', () => {
    expect(normalizeMessageForDedupe('  Hello World  ')).toBe('hello world');
    expect(normalizeMessageForDedupe('Hello\n\nWorld')).toBe('hello world');
    expect(normalizeMessageForDedupe('Hello   World')).toBe('hello world');
    expect(normalizeMessageForDedupe('HELLO WORLD')).toBe('hello world');
  });

  it('handles empty strings', () => {
    expect(normalizeMessageForDedupe('')).toBe('');
    expect(normalizeMessageForDedupe('   ')).toBe('');
  });
});

describe('isDuplicateOfLastBotFinal (runtime function)', () => {
  it('paired room: detects duplicate final message', () => {
    const jid = 'dc:paired-room';
    setupChat(jid);

    // Register as paired room
    _setRegisteredGroupForTests(jid, {
      name: 'Paired Room',
      folder: 'paired-room',
      trigger: '@claude',
      added_at: new Date().toISOString(),
      agentType: 'claude-code',
    });

    _setRegisteredGroupForTests(jid, {
      name: 'Paired Room',
      folder: 'paired-room',
      trigger: '@codex',
      added_at: new Date().toISOString(),
      agentType: 'codex',
    });

    // Store a bot message (from any bot)
    storeMessage(
      createMessage({
        id: 'msg-1',
        chat_jid: jid,
        content: 'DONE — Task completed successfully',
        timestamp: new Date().toISOString(),
        is_from_me: false, // Different bot
        is_bot_message: true,
      }),
    );

    // Verify it's a paired room
    expect(hasReviewerLease(jid)).toBe(true);

    // Verify duplicate detection works via the actual runtime function
    expect(
      isDuplicateOfLastBotFinal(jid, 'DONE — Task completed successfully'),
    ).toBe(true);
    expect(
      isDuplicateOfLastBotFinal(jid, 'done — task completed successfully'),
    ).toBe(true); // Normalized match
  });

  it('non-paired room: duplicate check is bypassed', () => {
    const jid = 'dc:single-bot';
    setupChat(jid);

    // Register only one bot
    _setRegisteredGroupForTests(jid, {
      name: 'Single Bot',
      folder: 'single-bot',
      trigger: '@claude',
      added_at: new Date().toISOString(),
      agentType: 'claude-code',
    });

    // Store a bot message
    storeMessage(
      createMessage({
        id: 'msg-1',
        chat_jid: jid,
        content: 'DONE — Task completed',
        timestamp: new Date().toISOString(),
        is_from_me: true,
        is_bot_message: true,
      }),
    );

    // Verify it's NOT a paired room
    expect(hasReviewerLease(jid)).toBe(false);

    // Duplicate check should be bypassed (return false)
    expect(isDuplicateOfLastBotFinal(jid, 'DONE — Task completed')).toBe(false);
  });

  it('non-duplicate message in paired room is not suppressed', () => {
    const jid = 'dc:paired-room';
    setupChat(jid);

    // Register as paired room
    _setRegisteredGroupForTests(jid, {
      name: 'Paired Room',
      folder: 'paired-room',
      trigger: '@claude',
      added_at: new Date().toISOString(),
      agentType: 'claude-code',
    });

    _setRegisteredGroupForTests(jid, {
      name: 'Paired Room',
      folder: 'paired-room',
      trigger: '@codex',
      added_at: new Date().toISOString(),
      agentType: 'codex',
    });

    // Store a bot message
    storeMessage(
      createMessage({
        id: 'msg-1',
        chat_jid: jid,
        content: 'First message content',
        timestamp: new Date().toISOString(),
        is_from_me: true,
        is_bot_message: true,
      }),
    );

    // Verify different content is not a duplicate
    expect(isDuplicateOfLastBotFinal(jid, 'Different message content')).toBe(
      false,
    );
    expect(isDuplicateOfLastBotFinal(jid, 'First message content')).toBe(true);
  });

  it('cross-bot duplicate detection: claude detects codex message as duplicate', () => {
    const jid = 'dc:paired-room';
    setupChat(jid);

    // Register as paired room
    _setRegisteredGroupForTests(jid, {
      name: 'Paired Room',
      folder: 'paired-room',
      trigger: '@claude',
      added_at: new Date().toISOString(),
      agentType: 'claude-code',
    });

    _setRegisteredGroupForTests(jid, {
      name: 'Paired Room',
      folder: 'paired-room',
      trigger: '@codex',
      added_at: new Date().toISOString(),
      agentType: 'codex',
    });

    // Store a bot message from "codex" (is_from_me=0)
    storeMessage(
      createMessage({
        id: 'msg-1',
        chat_jid: jid,
        content: 'DONE — Analysis complete',
        timestamp: new Date().toISOString(),
        is_from_me: false, // Other bot
        is_bot_message: true,
      }),
    );

    // Verify claude service detects this as duplicate (cross-bot detection)
    expect(isDuplicateOfLastBotFinal(jid, 'DONE — Analysis complete')).toBe(
      true,
    );
  });

  it('normalization handles whitespace and case differences', () => {
    const jid = 'dc:paired-room';
    setupChat(jid);

    // Register as paired room
    _setRegisteredGroupForTests(jid, {
      name: 'Paired Room',
      folder: 'paired-room',
      trigger: '@claude',
      added_at: new Date().toISOString(),
      agentType: 'claude-code',
    });

    _setRegisteredGroupForTests(jid, {
      name: 'Paired Room',
      folder: 'paired-room',
      trigger: '@codex',
      added_at: new Date().toISOString(),
      agentType: 'codex',
    });

    // Store a bot message with specific formatting
    storeMessage(
      createMessage({
        id: 'msg-1',
        chat_jid: jid,
        content: 'DONE — Task completed\n\nSuccessfully',
        timestamp: new Date().toISOString(),
        is_from_me: true,
        is_bot_message: true,
      }),
    );

    // Same content with different whitespace should be detected as duplicate
    expect(
      isDuplicateOfLastBotFinal(jid, 'done — task completed successfully'),
    ).toBe(true);
    expect(
      isDuplicateOfLastBotFinal(
        jid,
        '  DONE  —  Task  completed  Successfully  ',
      ),
    ).toBe(true);

    // Different content should not be duplicate
    expect(isDuplicateOfLastBotFinal(jid, 'FAILED — Task failed')).toBe(false);
  });

  it('work item lifecycle: produced -> delivered (duplicate)', () => {
    const jid = 'dc:paired-room';
    setupChat(jid);

    // Register as paired room
    _setRegisteredGroupForTests(jid, {
      name: 'Paired Room',
      folder: 'paired-room',
      trigger: '@claude',
      added_at: new Date().toISOString(),
      agentType: 'claude-code',
    });

    _setRegisteredGroupForTests(jid, {
      name: 'Paired Room',
      folder: 'paired-room',
      trigger: '@codex',
      added_at: new Date().toISOString(),
      agentType: 'codex',
    });

    // Store a bot message (simulating previous delivery)
    storeMessage(
      createMessage({
        id: 'msg-1',
        chat_jid: jid,
        content: 'DONE — Task completed successfully',
        timestamp: new Date().toISOString(),
        is_from_me: true,
        is_bot_message: true,
      }),
    );

    // Create a work item with the same content (duplicate)
    const workItem = createProducedWorkItem({
      group_folder: 'paired-room',
      chat_jid: jid,
      agent_type: 'claude-code',
      start_seq: 1,
      end_seq: 2,
      result_payload: 'DONE — Task completed successfully',
    });

    expect(workItem.status).toBe('produced');

    // Verify duplicate detection via actual runtime function
    expect(isDuplicateOfLastBotFinal(jid, workItem.result_payload)).toBe(true);

    // Simulate suppression: mark as delivered without sending
    markWorkItemDelivered(workItem.id, null);

    // Verify work item is marked delivered
    const openItem = getOpenWorkItem(jid, 'claude-code');
    expect(openItem).toBeUndefined(); // No open items because it was marked delivered
  });

  it('work item lifecycle: produced -> pending -> delivered (non-duplicate)', () => {
    const jid = 'dc:paired-room';
    setupChat(jid);

    // Register as paired room
    _setRegisteredGroupForTests(jid, {
      name: 'Paired Room',
      folder: 'paired-room',
      trigger: '@claude',
      added_at: new Date().toISOString(),
      agentType: 'claude-code',
    });

    _setRegisteredGroupForTests(jid, {
      name: 'Paired Room',
      folder: 'paired-room',
      trigger: '@codex',
      added_at: new Date().toISOString(),
      agentType: 'codex',
    });

    // Store a bot message
    storeMessage(
      createMessage({
        id: 'msg-1',
        chat_jid: jid,
        content: 'First message',
        timestamp: new Date().toISOString(),
        is_from_me: true,
        is_bot_message: true,
      }),
    );

    // Create a work item with DIFFERENT content (non-duplicate)
    const workItem = createProducedWorkItem({
      group_folder: 'paired-room',
      chat_jid: jid,
      agent_type: 'claude-code',
      start_seq: 1,
      end_seq: 2,
      result_payload: 'Second message (different)',
    });

    expect(workItem.status).toBe('produced');

    // Verify NOT a duplicate
    expect(isDuplicateOfLastBotFinal(jid, workItem.result_payload)).toBe(false);
  });
});
