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

import { mapOperationToPayment, mapServerToVps } from './mappers.js'
import type { UserApiOperation, UserApiServerDetail } from './operations.js'

const server: UserApiServerDetail = {
  id: 12345,
  name: 'Server #12345',
  full_name: 'Server 2 RAM / 1 CPU / 40 NVMe #12345',
  created: '2022-02-24',
  end: '2029-02-20',
  status: 'active',
  host: 'super.server.host',
  ip: { id: 1, ip: '91.84.101.78', type: '4' },
  template: { id: 23, name: 'Ubuntu 24.04' },
  datacenter: { id: 1, name: 'Amsterdam 1', country: 'nl' },
  'server-plan': { id: 1, name: '2 RAM / 1 CPU / 40 NVMe' },
  data: {
    cpu: { value: 1 },
    ram: { value: 2 },
    disk: { value: 40 },
    traff: { value: 32, for: 'Tb' },
  },
}

describe('mapServerToVps', () => {
  it('maps macloud server with apiType prefix in notes', () => {
    const planIndex = new Map([
      [
        '1',
        {
          id: 1,
          name: '2 RAM / 1 CPU / 40 NVMe',
          cost: 1.55,
          period: 'day',
        },
      ],
    ])
    const vps = mapServerToVps(server, 'macloud', 'prov-1', 'acc-1', planIndex)
    expect(vps.externalId).toBe('12345')
    expect(vps.ip).toBe('91.84.101.78')
    expect(vps.os).toBe('Ubuntu 24.04')
    expect(vps.vcpu).toBe(1)
    expect(vps.ramGb).toBe(2)
    expect(vps.diskGb).toBe(40)
    expect(vps.bandwidthTb).toBe(32)
    expect(vps.country).toBe('NL')
    expect(vps.paidUntil).toBe('2029-02-20')
    expect(vps.notes).toContain('macloud-12345')
    expect(vps.tariffType).toBe('daily')
    expect(vps.dailyRate).toBe(1.55)
    expect(vps.monthlyRate).toBe(46.5)
    expect(vps.currency).toBe('RUB')
  })

  it('resolves plan by server-group scoped index key', () => {
    const planIndex = new Map([
      [
        '11:1',
        {
          id: 1,
          name: 'Wrong group plan',
          cost: 0,
          full_cost: 9.99,
          period: 'day',
          'server-group': 11,
        },
      ],
      [
        '5:1',
        {
          id: 1,
          name: '2 RAM / 1 CPU / 40 NVMe',
          cost: 2.5,
          period: 'day',
          'server-group': 5,
        },
      ],
    ])
    const vps = mapServerToVps(
      { ...server, 'server-group': { id: 5, name: 'VDS' } },
      'vdsina',
      'prov-1',
      'acc-1',
      planIndex,
      'USD',
    )
    expect(vps.dailyRate).toBe(2.5)
  })

  it('uses full_cost when discounted cost is zero', () => {
    const planIndex = new Map([
      [
        '1',
        {
          id: 1,
          name: '2 RAM / 1 CPU / 40 NVMe',
          cost: 0,
          full_cost: 1.55,
          period: 'day',
        },
      ],
    ])
    const vps = mapServerToVps(server, 'macloud', 'prov-1', 'acc-1', planIndex)
    expect(vps.dailyRate).toBe(1.55)
    expect(vps.monthlyRate).toBe(46.5)
  })

  it('maps macloud monthly plan when period fields are missing', () => {
    const planIndex = new Map([
      [
        '3:7',
        {
          id: 7,
          name: '1 RAM / 1 CPU / 10 NVMe',
          cost: 150,
          period: '',
          'server-group': 3,
        },
      ],
    ])
    const vps = mapServerToVps(
      {
        ...server,
        'server-plan': { id: 7, name: '1 RAM / 1 CPU / 10 NVMe' },
        'server-group': { id: 3, name: 'VDS' },
        data: { cpu: { value: 1 }, ram: { value: 1 }, disk: { value: 10 } },
      },
      'macloud',
      'prov-1',
      'acc-1',
      planIndex,
      'RUB',
    )
    expect(vps.tariffType).toBe('monthly')
    expect(vps.monthlyRate).toBe(150)
    expect(vps.dailyRate).toBeNull()
  })

  it('parses string plan cost from index', () => {
    const planIndex = new Map([
      [
        '1',
        {
          id: 1,
          name: 'Plan',
          cost: '2.50',
          period: 'day',
        },
      ],
    ])
    const vps = mapServerToVps(server, 'vdsina', 'prov-1', 'acc-1', planIndex, 'USD')
    expect(vps.dailyRate).toBe(2.5)
    expect(vps.currency).toBe('USD')
  })

  it('falls back to tariff item price when plan index misses', () => {
    const tariffByPlanId = new Map([
      [
        '1',
        {
          externalId: '1',
          datacenterKey: '11',
          datacenterName: 'Cloud',
          name: 'Plan',
          desc: '',
          vcpu: 1,
          ramGb: 1,
          diskGb: 10,
          diskType: 'NVMe',
          virtualization: 'KVM',
          channel: '',
          location: 'Cloud',
          country: '',
          cpuModel: '',
          orderAvailable: true,
          price: '3 USD/day',
        },
      ],
    ])
    const vps = mapServerToVps(server, 'vdsina', 'prov-1', 'acc-1', undefined, 'USD', tariffByPlanId)
    expect(vps.dailyRate).toBe(3)
    expect(vps.monthlyRate).toBe(90)
    expect(vps.currency).toBe('USD')
  })

  it('maps monthly plan cost from plan index', () => {
    const planIndex = new Map([
      [
        '1',
        {
          id: 1,
          name: '2 RAM / 1 CPU / 40 NVMe',
          cost: 500,
          period: 'month',
        },
      ],
    ])
    const vps = mapServerToVps(server, 'vdsina', 'prov-1', 'acc-1', planIndex)
    expect(vps.tariffType).toBe('monthly')
    expect(vps.monthlyRate).toBe(500)
    expect(vps.dailyRate).toBeNull()
  })

  it('adds constructor plan extra cost from server totals', () => {
    const planIndex = new Map([
      [
        '1',
        {
          id: 1,
          name: 'Constructor',
          cost: 10,
          period: 'day',
          has_params: true,
          params: {
            cpu: { cost: 1 },
            ram: { cost: 0.5 },
            disk: { cost: 0.1 },
          },
          data: { cpu: { value: 1 }, ram: { value: 1 }, disk: { value: 1 } },
        },
      ],
    ])
    const vps = mapServerToVps(
      {
        ...server,
        data: {
          cpu: { value: 1, total: 4 },
          ram: { value: 1, total: 8 },
          disk: { value: 1, total: 10 },
        },
      },
      'vdsina',
      'prov-1',
      'acc-1',
      planIndex,
    )
    // 10 + 3*1 + 7*0.5 + 9*0.1 = 10 + 3 + 3.5 + 0.9 = 17.4
    expect(vps.dailyRate).toBe(17.4)
  })

  it('maps vdsina server with vdsina prefix in notes', () => {
    const vps = mapServerToVps(server, 'vdsina', 'prov-2', 'acc-2')
    expect(vps.notes).toContain('vdsina-12345')
  })

  it('maps paused status for notpaid', () => {
    const vps = mapServerToVps({ ...server, status: 'notpaid' }, 'macloud', 'p', 'a')
    expect(vps.status).toBe('paused')
  })
})

describe('mapOperationToPayment', () => {
  const topup: UserApiOperation = {
    id: 4290676,
    purse: 'real',
    type: 1,
    status: 1,
    summ: '100',
    created: '2025-02-22 12:28:23',
    comment: 'Balance replenishment',
  }

  it('maps paid credit to provider_balance_topup', () => {
    const payment = mapOperationToPayment(topup, 'macloud', 'acc-1')
    expect(payment).toMatchObject({
      externalId: '4290676',
      type: 'provider_balance_topup',
      amount: 100,
      date: '2025-02-22',
      note: 'Balance replenishment',
    })
  })

  it('returns null for debit operations', () => {
    expect(mapOperationToPayment({ ...topup, type: -1 }, 'vdsina', 'acc-1')).toBeNull()
  })

  it('returns null for unpaid operations', () => {
    expect(mapOperationToPayment({ ...topup, status: 0 }, 'macloud', 'acc-1')).toBeNull()
  })
})
