import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { closeDb, getSqlite } from '@cfdm/db'
import { resetTestDb } from '@cfdm/db/test-setup'
import { providerAccountsRepository } from '@cfdm/db/repositories/provider-accounts'

import { syncFromUserApi } from './sync.js'
import type { UserApiSyncAccount } from './context.js'

vi.mock('./operations.js', async (importOriginal) => {
  const actual = await importOriginal<typeof import('./operations.js')>()
  return {
    ...actual,
    fetchServersWithDetails: vi.fn(),
    fetchBalance: vi.fn(),
    fetchTariffList: vi.fn(),
    fetchPlanCostIndex: vi.fn(),
    fetchOperations: vi.fn(),
  }
})

import {
  fetchBalance,
  fetchOperations,
  fetchPlanCostIndex,
  fetchServersWithDetails,
  fetchTariffList,
} from './operations.js'

function makeAccount(apiType: 'macloud' | 'vdsina'): UserApiSyncAccount {
  return {
    id: `acc-${apiType}`,
    spaceId: 'space-main',
    providerId: `prov-${apiType}`,
    name: `${apiType} Account`,
    panelUrl: '',
    currency: 'RUB',
    billingMode: 'daily',
    notes: '',
    apiType,
    apiBaseUrl:
      apiType === 'macloud'
        ? 'https://userapi.macloud.ru/v1'
        : 'https://userapi.vdsina.com/v1',
    apiCredentials: 'secret-token',
    apiToken: 'secret-token',
    balanceApi: null,
    balanceCurrency: null,
    balanceUpdatedAt: null,
    enoughmoneyto: '',
    balanceAlertBelow: null,
    providerBaseCurrency: null,
  }
}

describe('syncFromUserApi', () => {
  beforeEach(() => {
    resetTestDb()
    vi.mocked(fetchServersWithDetails).mockResolvedValue([
      {
        id: 100,
        name: 'Server #100',
        status: 'active',
        end: '2029-01-01',
        ip: { ip: '1.2.3.4', type: '4' },
        template: { name: 'Debian 12' },
        datacenter: { id: 1, name: 'DC1', country: 'ru' },
        'server-plan': { id: 13, name: '2 RAM / 1 CPU / 40 NVMe' },
        data: { cpu: { value: 1 }, ram: { value: 2 }, disk: { value: 40 } },
      },
    ])
    vi.mocked(fetchBalance).mockResolvedValue({
      balance: 500,
      currency: 'RUB',
      enoughmoneyto: '2029-12-01',
    })
    vi.mocked(fetchTariffList).mockResolvedValue([
      {
        externalId: '13',
        datacenterKey: '11',
        datacenterName: 'Cloud',
        name: '2 RAM / 1 CPU / 40 NVMe',
        desc: '',
        vcpu: 1,
        ramGb: 2,
        diskGb: 40,
        diskType: 'NVMe',
        virtualization: 'KVM',
        channel: '',
        location: 'Cloud',
        country: '',
        cpuModel: '',
        orderAvailable: true,
        price: '1.55 RUB/day',
      },
    ])
    vi.mocked(fetchPlanCostIndex).mockResolvedValue(
      new Map([
        [
          '13',
          {
            id: 13,
            name: '2 RAM / 1 CPU / 40 NVMe',
            cost: 1.55,
            period: 'day',
          },
        ],
      ]),
    )
    vi.mocked(fetchOperations).mockResolvedValue([
      {
        id: 999,
        purse: 'real',
        type: 1,
        status: 1,
        summ: '200',
        created: '2025-03-01 10:00:00',
        comment: 'Top up',
      },
    ])
  })

  afterEach(() => {
    closeDb()
  })

  it('syncs macloud account with correct id prefix', async () => {
    getSqlite()
      .prepare(
        `INSERT INTO providers (id, name, apiType, apiBaseUrl) VALUES ('prov-macloud', 'Macloud', 'macloud', 'https://userapi.macloud.ru/v1')`,
      )
      .run()
    providerAccountsRepository.create({
      id: 'acc-macloud',
      providerId: 'prov-macloud',
      name: 'Macloud',
      apiCredentials: 'secret-token',
    })

    const result = await syncFromUserApi(makeAccount('macloud'))

    expect(result.vpsCount).toBe(1)
    expect(result.paymentsCount).toBe(1)
    expect(result.tariffsCount).toBe(1)
    expect(result.balance?.balance).toBe(500)

    const vps = getSqlite().prepare('SELECT id, notes, dailyRate, tariffType FROM vps WHERE id = ?').get('vps-macloud-acc-macloud-100') as {
      id: string
      notes: string
      dailyRate: number
      tariffType: string
    }
    expect(vps.notes).toContain('macloud-100')
    expect(vps.dailyRate).toBe(1.55)
    expect(vps.tariffType).toBe('daily')
  })

  it('syncs vdsina account with vdsina id prefix', async () => {
    getSqlite()
      .prepare(
        `INSERT INTO providers (id, name, apiType, apiBaseUrl, baseCurrency) VALUES ('prov-vdsina', 'VDSina', 'vdsina', 'https://userapi.vdsina.com/v1', 'USD')`,
      )
      .run()
    providerAccountsRepository.create({
      id: 'acc-vdsina',
      providerId: 'prov-vdsina',
      name: 'VDSina',
      apiCredentials: 'secret-token',
    })

    const result = await syncFromUserApi({
      ...makeAccount('vdsina'),
      providerBaseCurrency: 'USD',
    })

    expect(result.vpsCount).toBe(1)
    const vps = getSqlite()
      .prepare('SELECT id, currency, dailyRate, monthlyRate FROM vps WHERE id = ?')
      .get('vps-vdsina-acc-vdsina-100') as {
      id: string
      currency: string
      dailyRate: number
      monthlyRate: number
    }
    expect(vps).toBeTruthy()
    expect(vps.currency).toBe('USD')
    expect(vps.dailyRate).toBe(1.55)
    expect(vps.monthlyRate).toBe(46.5)
  })
})
