import { describe, it, expect, beforeEach, vi } from 'vitest';
import Fastify, { FastifyInstance } from 'fastify';
import telegramManagementRoutes from './telegram-management.js';

// Mock file-ops to avoid real filesystem access
vi.mock('../modules/data-store/file-ops.js', () => ({
  readJSON: vi.fn().mockResolvedValue([]),
  atomicWriteJSON: vi.fn().mockResolvedValue(undefined),
}));

function createMockUserbotClient(overrides: Record<string, any> = {}) {
  return {
    createGroup: vi.fn().mockResolvedValue({ chatId: 12345, inviteLink: 'https://t.me/+abc123' }),
    createChannel: vi.fn().mockResolvedValue({ chatId: 67890, inviteLink: 'https://t.me/+xyz789' }),
    sendMessage: vi.fn().mockResolvedValue(undefined),
    ...overrides,
  };
}

function createMockUserbotManager(client: any = null) {
  return {
    getClient: vi.fn().mockReturnValue(client),
  } as any;
}

function createMockDataStore() {
  return {} as any;
}

async function buildApp(opts: { client?: any } = {}): Promise<{
  app: FastifyInstance;
  userbotManager: any;
}> {
  const app = Fastify();
  const client = opts.client ?? null;
  const userbotManager = createMockUserbotManager(client);
  await app.register(telegramManagementRoutes, {
    userbotManager,
    dataStore: createMockDataStore(),
  });
  return { app, userbotManager };
}

describe('telegram-management routes', () => {
  describe('POST /characters/:id/telegram/groups', () => {
    it('returns 400 when no active userbot session', async () => {
      const { app } = await buildApp();
      const res = await app.inject({
        method: 'POST',
        url: '/characters/char-1/telegram/groups',
        payload: { title: 'Test Group' },
      });
      expect(res.statusCode).toBe(400);
      const body = res.json();
      expect(body.success).toBe(false);
      expect(body.error).toBe('Bu karakter için aktif userbot oturumu yok');
    });

    it('returns 400 when title is missing', async () => {
      const client = createMockUserbotClient();
      const { app } = await buildApp({ client });
      const res = await app.inject({
        method: 'POST',
        url: '/characters/char-1/telegram/groups',
        payload: { description: 'No title' },
      });
      expect(res.statusCode).toBe(400);
      expect(res.json().error).toContain('title');
    });

    it('creates group with real GramJS chatId', async () => {
      const client = createMockUserbotClient();
      const { app } = await buildApp({ client });
      const res = await app.inject({
        method: 'POST',
        url: '/characters/char-1/telegram/groups',
        payload: { title: 'My Group', description: 'A test group', groupType: 'normal' },
      });
      expect(res.statusCode).toBe(201);
      const body = res.json();
      expect(body.success).toBe(true);
      expect(body.data.telegramChatId).toBe(12345);
      expect(body.data.inviteLink).toBe('https://t.me/+abc123');
      expect(body.data.type).toBe('group');
      expect(body.data.title).toBe('My Group');
      expect(client.createGroup).toHaveBeenCalledWith('My Group', 'A test group', false);
    });

    it('creates supergroup with real GramJS chatId', async () => {
      const client = createMockUserbotClient({
        createGroup: vi.fn().mockResolvedValue({ chatId: 99999, inviteLink: 'https://t.me/+super' }),
      });
      const { app } = await buildApp({ client });
      const res = await app.inject({
        method: 'POST',
        url: '/characters/char-1/telegram/groups',
        payload: { title: 'Super Group', groupType: 'supergroup' },
      });
      expect(res.statusCode).toBe(201);
      const body = res.json();
      expect(body.data.telegramChatId).toBe(99999);
      expect(body.data.type).toBe('supergroup');
      expect(client.createGroup).toHaveBeenCalledWith('Super Group', undefined, true);
    });

    it('returns 502 with retryable flag on GramJS error', async () => {
      const client = createMockUserbotClient({
        createGroup: vi.fn().mockRejectedValue(new Error('FLOOD_WAIT_30')),
      });
      const { app } = await buildApp({ client });
      const res = await app.inject({
        method: 'POST',
        url: '/characters/char-1/telegram/groups',
        payload: { title: 'Fail Group' },
      });
      expect(res.statusCode).toBe(502);
      const body = res.json();
      expect(body.success).toBe(false);
      expect(body.error).toContain('Telegram işlemi başarısız');
      expect(body.error).toContain('FLOOD_WAIT_30');
      expect(body.retryable).toBe(true);
    });
  });

  describe('POST /characters/:id/telegram/channels', () => {
    it('returns 400 when no active userbot session', async () => {
      const { app } = await buildApp();
      const res = await app.inject({
        method: 'POST',
        url: '/characters/char-1/telegram/channels',
        payload: { title: 'Test Channel' },
      });
      expect(res.statusCode).toBe(400);
      expect(res.json().error).toBe('Bu karakter için aktif userbot oturumu yok');
    });

    it('creates channel with real GramJS chatId', async () => {
      const client = createMockUserbotClient();
      const { app } = await buildApp({ client });
      const res = await app.inject({
        method: 'POST',
        url: '/characters/char-1/telegram/channels',
        payload: { title: 'My Channel', description: 'A test channel', channelType: 'public' },
      });
      expect(res.statusCode).toBe(201);
      const body = res.json();
      expect(body.success).toBe(true);
      expect(body.data.telegramChatId).toBe(67890);
      expect(body.data.inviteLink).toBe('https://t.me/+xyz789');
      expect(body.data.type).toBe('channel');
      expect(body.data.isVip).toBe(false);
      expect(client.createChannel).toHaveBeenCalledWith('My Channel', 'A test channel');
    });

    it('creates VIP channel with starPrice', async () => {
      const client = createMockUserbotClient();
      const { app } = await buildApp({ client });
      const res = await app.inject({
        method: 'POST',
        url: '/characters/char-1/telegram/channels',
        payload: { title: 'VIP Channel', channelType: 'vip', starPrice: 100 },
      });
      expect(res.statusCode).toBe(201);
      const body = res.json();
      expect(body.data.isVip).toBe(true);
      expect(body.data.starPrice).toBe(100);
      expect(body.data.telegramChatId).toBe(67890);
    });

    it('returns 502 with retryable flag on GramJS error', async () => {
      const client = createMockUserbotClient({
        createChannel: vi.fn().mockRejectedValue(new Error('CHANNELS_TOO_MUCH')),
      });
      const { app } = await buildApp({ client });
      const res = await app.inject({
        method: 'POST',
        url: '/characters/char-1/telegram/channels',
        payload: { title: 'Fail Channel' },
      });
      expect(res.statusCode).toBe(502);
      const body = res.json();
      expect(body.retryable).toBe(true);
      expect(body.error).toContain('CHANNELS_TOO_MUCH');
    });
  });

  describe('POST /characters/:id/telegram/entities/:entityId/publish', () => {
    it('returns 400 when no active userbot session', async () => {
      // Need to set up entities so entity is found first
      const { readJSON } = await import('../modules/data-store/file-ops.js');
      (readJSON as any).mockResolvedValue([
        { id: 'ent-1', characterId: 'char-1', telegramChatId: 12345, type: 'channel', title: 'Ch' },
      ]);

      const { app } = await buildApp();
      const res = await app.inject({
        method: 'POST',
        url: '/characters/char-1/telegram/entities/ent-1/publish',
        payload: { text: 'Hello world' },
      });
      expect(res.statusCode).toBe(400);
      expect(res.json().error).toBe('Bu karakter için aktif userbot oturumu yok');
    });

    it('publishes content via real GramJS sendMessage', async () => {
      const { readJSON } = await import('../modules/data-store/file-ops.js');
      (readJSON as any).mockResolvedValue([
        { id: 'ent-1', characterId: 'char-1', telegramChatId: 12345, type: 'channel', title: 'Ch' },
      ]);

      const client = createMockUserbotClient();
      const { app } = await buildApp({ client });
      const res = await app.inject({
        method: 'POST',
        url: '/characters/char-1/telegram/entities/ent-1/publish',
        payload: { text: 'Hello world', imageUrl: 'https://example.com/img.jpg' },
      });
      expect(res.statusCode).toBe(200);
      const body = res.json();
      expect(body.success).toBe(true);
      expect(body.data.published).toBe(true);
      expect(client.sendMessage).toHaveBeenCalledWith(12345, 'Hello world', 'https://example.com/img.jpg');
    });

    it('returns 502 with retryable flag on GramJS sendMessage error', async () => {
      const { readJSON } = await import('../modules/data-store/file-ops.js');
      (readJSON as any).mockResolvedValue([
        { id: 'ent-1', characterId: 'char-1', telegramChatId: 12345, type: 'channel', title: 'Ch' },
      ]);

      const client = createMockUserbotClient({
        sendMessage: vi.fn().mockRejectedValue(new Error('PEER_ID_INVALID')),
      });
      const { app } = await buildApp({ client });
      const res = await app.inject({
        method: 'POST',
        url: '/characters/char-1/telegram/entities/ent-1/publish',
        payload: { text: 'Hello' },
      });
      expect(res.statusCode).toBe(502);
      const body = res.json();
      expect(body.retryable).toBe(true);
      expect(body.error).toContain('PEER_ID_INVALID');
    });

    it('returns 404 when entity not found', async () => {
      const { readJSON } = await import('../modules/data-store/file-ops.js');
      (readJSON as any).mockResolvedValue([]);

      const client = createMockUserbotClient();
      const { app } = await buildApp({ client });
      const res = await app.inject({
        method: 'POST',
        url: '/characters/char-1/telegram/entities/nonexistent/publish',
        payload: { text: 'Hello' },
      });
      expect(res.statusCode).toBe(404);
    });
  });
});
