import { beforeEach, describe, expect, it, vi } from 'vitest'
import { Hono } from 'hono'
import type { AppEnv } from '../src/types'

const mockGetTaskSyncSettings = vi.fn()
const mockUpsertTaskSyncSettings = vi.fn()
const mockAssertTenantOwnsProject = vi.fn()
const mockRunTaskSync = vi.fn()

vi.mock('../src/middleware/guards', () => ({
  requirePermission: () => async (_c: unknown, next: () => Promise<void>) => next(),
}))

vi.mock('@zync/db/queries', () => ({
  createDb: vi.fn(() => ({})),
  getTaskSyncSettings: (...args: unknown[]) => mockGetTaskSyncSettings(...args),
  upsertTaskSyncSettings: (...args: unknown[]) => mockUpsertTaskSyncSettings(...args),
  assertTenantOwnsProject: (...args: unknown[]) => mockAssertTenantOwnsProject(...args),
  invalidTenantReferenceBody: (field: string) => ({ error: `invalid_${field}` }),
}))

vi.mock('../src/routes/cron/tasks-sync', () => ({
  runTaskSync: (...args: unknown[]) => mockRunTaskSync(...args),
}))

import { taskSettingsRoute } from '../src/routes/tasks/settings'

function appFor() {
  const app = new Hono<AppEnv>()
  app.use('*', async (c, next) => {
    c.set('session', {
      type: 'user',
      sub: 'user-1',
      tid: 'tenant-1',
      role: 'OWNER',
      permissions: ['tasks:read', 'tasks:write'],
    })
    c.set('db', {})
    await next()
  })
  app.route('/api/tasks', taskSettingsRoute)
  return app
}

describe('task sync settings routes', () => {
  beforeEach(() => {
    vi.clearAllMocks()
    mockAssertTenantOwnsProject.mockResolvedValue(true)
    mockRunTaskSync.mockResolvedValue([
      { tenantId: 'tenant-1', adapterId: 'trello', status: 'success', itemsCount: 2 },
    ])
  })

  it('returns default sync settings when none are stored', async () => {
    mockGetTaskSyncSettings.mockResolvedValue(null)

    const res = await appFor().request('/api/tasks/settings/sync')

    expect(res.status).toBe(200)
    await expect(res.json()).resolves.toEqual({
      sync_interval_minutes: 120,
      auto_create_tickets_from: {},
      default_project_id: null,
    })
  })

  it('persists sync settings and validates default project ownership', async () => {
    const PROJECT_UUID = '00000000-0000-4000-8000-000000000001'
    mockUpsertTaskSyncSettings.mockResolvedValue({
      syncIntervalMinutes: 240,
      autoCreateTicketsFrom: { email: true, slack: false },
      defaultProjectId: PROJECT_UUID,
    })

    const res = await appFor().request('/api/tasks/settings/sync', {
      method: 'PATCH',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        sync_interval_minutes: 240,
        auto_create_tickets_from: { email: true, slack: false },
        default_project_id: PROJECT_UUID,
      }),
    })

    expect(res.status).toBe(200)
    expect(mockAssertTenantOwnsProject).toHaveBeenCalledWith({}, 'tenant-1', PROJECT_UUID)
    expect(mockUpsertTaskSyncSettings).toHaveBeenCalledWith({}, 'tenant-1', {
      syncIntervalMinutes: 240,
      autoCreateTicketsFrom: { email: true, slack: false },
      defaultProjectId: PROJECT_UUID,
    })
  })

  it('runs a manual sync for the active tenant', async () => {
    const res = await appFor().request('/api/tasks/settings/sync/run', { method: 'POST' })

    expect(res.status).toBe(200)
    expect(mockRunTaskSync).toHaveBeenCalledWith({
      db: {},
      env: undefined,
      tenantIds: ['tenant-1'],
      force: true,
    })
  })
})
