import { describe, it, expect } from 'bun:test'
import {
  TransactionCreateSchema,
  TransactionLineItemCreateSchema,
  ApplyDiscountSchema,
  CompleteTransactionSchema,
  DiscountCreateSchema,
  DiscountUpdateSchema,
  DrawerOpenSchema,
  DrawerCloseSchema,
  TransactionType,
  TransactionStatus,
  PaymentMethod,
  DiscountType,
  DiscountAppliesTo,
  DrawerStatus,
  TaxCategory,
} from '../../src/schemas/pos.schema.js'

// ─── Enums ───────────────────────────────────────────────────────────────────

describe('POS enums', () => {
  it('TransactionType accepts valid values', () => {
    expect(TransactionType.parse('sale')).toBe('sale')
    expect(TransactionType.parse('repair_payment')).toBe('repair_payment')
    expect(TransactionType.parse('refund')).toBe('refund')
  })

  it('TransactionType rejects invalid value', () => {
    expect(() => TransactionType.parse('layaway')).toThrow()
  })

  it('TransactionStatus accepts valid values', () => {
    expect(TransactionStatus.parse('pending')).toBe('pending')
    expect(TransactionStatus.parse('voided')).toBe('voided')
  })

  it('PaymentMethod accepts valid values', () => {
    expect(PaymentMethod.parse('cash')).toBe('cash')
    expect(PaymentMethod.parse('card_present')).toBe('card_present')
    expect(PaymentMethod.parse('account_charge')).toBe('account_charge')
  })

  it('TaxCategory accepts valid values', () => {
    expect(TaxCategory.parse('goods')).toBe('goods')
    expect(TaxCategory.parse('service')).toBe('service')
    expect(TaxCategory.parse('exempt')).toBe('exempt')
  })

  it('TaxCategory rejects invalid value', () => {
    expect(() => TaxCategory.parse('luxury')).toThrow()
  })
})

// ─── TransactionCreateSchema ─────────────────────────────────────────────────

describe('TransactionCreateSchema', () => {
  it('parses minimal valid input', () => {
    const result = TransactionCreateSchema.parse({ transactionType: 'sale' })
    expect(result.transactionType).toBe('sale')
    expect(result.taxExempt).toBe(false)
  })

  it('parses full input with optional fields', () => {
    const result = TransactionCreateSchema.parse({
      transactionType: 'repair_payment',
      locationId: '10000000-1000-4000-8000-000000000001',
      accountId: '10000000-1000-4000-8000-000000000002',
      taxExempt: true,
      taxExemptReason: 'Non-profit',
      notes: 'Customer walkup',
    })
    expect(result.transactionType).toBe('repair_payment')
    expect(result.taxExempt).toBe(true)
    expect(result.taxExemptReason).toBe('Non-profit')
  })

  it('rejects missing transactionType', () => {
    expect(() => TransactionCreateSchema.parse({})).toThrow()
  })

  it('coerces empty string locationId to undefined', () => {
    const result = TransactionCreateSchema.parse({ transactionType: 'sale', locationId: '' })
    expect(result.locationId).toBeUndefined()
  })

  it('rejects invalid UUID for locationId', () => {
    expect(() =>
      TransactionCreateSchema.parse({ transactionType: 'sale', locationId: 'not-a-uuid' })
    ).toThrow()
  })
})

// ─── TransactionLineItemCreateSchema ─────────────────────────────────────────

describe('TransactionLineItemCreateSchema', () => {
  it('parses valid line item', () => {
    const result = TransactionLineItemCreateSchema.parse({
      description: 'Violin Strings',
      qty: 2,
      unitPrice: 12.99,
    })
    expect(result.description).toBe('Violin Strings')
    expect(result.qty).toBe(2)
    expect(result.unitPrice).toBe(12.99)
  })

  it('defaults qty to 1', () => {
    const result = TransactionLineItemCreateSchema.parse({
      description: 'Capo',
      unitPrice: 19.99,
    })
    expect(result.qty).toBe(1)
  })

  it('coerces string unitPrice to number', () => {
    const result = TransactionLineItemCreateSchema.parse({
      description: 'Pick',
      unitPrice: '5.99',
    })
    expect(result.unitPrice).toBe(5.99)
  })

  it('rejects empty description', () => {
    expect(() =>
      TransactionLineItemCreateSchema.parse({ description: '', unitPrice: 10 })
    ).toThrow()
  })

  it('rejects description over 255 chars', () => {
    expect(() =>
      TransactionLineItemCreateSchema.parse({ description: 'x'.repeat(256), unitPrice: 10 })
    ).toThrow()
  })

  it('rejects negative unitPrice', () => {
    expect(() =>
      TransactionLineItemCreateSchema.parse({ description: 'Bad', unitPrice: -1 })
    ).toThrow()
  })

  it('rejects qty of 0', () => {
    expect(() =>
      TransactionLineItemCreateSchema.parse({ description: 'Zero', qty: 0, unitPrice: 10 })
    ).toThrow()
  })

  it('rejects non-integer qty', () => {
    expect(() =>
      TransactionLineItemCreateSchema.parse({ description: 'Frac', qty: 1.5, unitPrice: 10 })
    ).toThrow()
  })
})

// ─── ApplyDiscountSchema ─────────────────────────────────────────────────────

describe('ApplyDiscountSchema', () => {
  it('parses valid discount application', () => {
    const result = ApplyDiscountSchema.parse({
      amount: 10,
      reason: 'Employee discount',
      lineItemId: '10000000-1000-4000-8000-000000000001',
    })
    expect(result.amount).toBe(10)
    expect(result.reason).toBe('Employee discount')
  })

  it('rejects missing reason', () => {
    expect(() => ApplyDiscountSchema.parse({ amount: 5 })).toThrow()
  })

  it('rejects empty reason', () => {
    expect(() => ApplyDiscountSchema.parse({ amount: 5, reason: '' })).toThrow()
  })

  it('rejects negative amount', () => {
    expect(() => ApplyDiscountSchema.parse({ amount: -1, reason: 'Nope' })).toThrow()
  })

  it('allows zero amount', () => {
    const result = ApplyDiscountSchema.parse({ amount: 0, reason: 'Remove discount' })
    expect(result.amount).toBe(0)
  })
})

// ─── CompleteTransactionSchema ───────────────────────────────────────────────

describe('CompleteTransactionSchema', () => {
  it('parses cash payment with amount tendered', () => {
    const result = CompleteTransactionSchema.parse({
      paymentMethod: 'cash',
      amountTendered: 50,
    })
    expect(result.paymentMethod).toBe('cash')
    expect(result.amountTendered).toBe(50)
  })

  it('parses card payment without amount tendered', () => {
    const result = CompleteTransactionSchema.parse({ paymentMethod: 'card_present' })
    expect(result.paymentMethod).toBe('card_present')
    expect(result.amountTendered).toBeUndefined()
  })

  it('parses check payment with check number', () => {
    const result = CompleteTransactionSchema.parse({
      paymentMethod: 'check',
      checkNumber: '1234',
    })
    expect(result.checkNumber).toBe('1234')
  })

  it('rejects missing paymentMethod', () => {
    expect(() => CompleteTransactionSchema.parse({})).toThrow()
  })

  it('rejects invalid payment method', () => {
    expect(() => CompleteTransactionSchema.parse({ paymentMethod: 'bitcoin' })).toThrow()
  })

  it('rejects check number over 50 chars', () => {
    expect(() =>
      CompleteTransactionSchema.parse({ paymentMethod: 'check', checkNumber: 'x'.repeat(51) })
    ).toThrow()
  })
})

// ─── DiscountCreateSchema ────────────────────────────────────────────────────

describe('DiscountCreateSchema', () => {
  it('parses valid discount', () => {
    const result = DiscountCreateSchema.parse({
      name: '10% Off',
      discountType: 'percent',
      discountValue: 10,
    })
    expect(result.name).toBe('10% Off')
    expect(result.appliesTo).toBe('line_item') // default
    expect(result.isActive).toBe(true) // default
  })

  it('rejects missing name', () => {
    expect(() => DiscountCreateSchema.parse({ discountType: 'fixed', discountValue: 5 })).toThrow()
  })

  it('rejects empty name', () => {
    expect(() =>
      DiscountCreateSchema.parse({ name: '', discountType: 'fixed', discountValue: 5 })
    ).toThrow()
  })

  it('accepts order-level discount', () => {
    const result = DiscountCreateSchema.parse({
      name: 'Order Disc',
      discountType: 'fixed',
      discountValue: 20,
      appliesTo: 'order',
    })
    expect(result.appliesTo).toBe('order')
  })

  it('accepts optional approval threshold', () => {
    const result = DiscountCreateSchema.parse({
      name: 'Big Disc',
      discountType: 'percent',
      discountValue: 50,
      requiresApprovalAbove: 25,
    })
    expect(result.requiresApprovalAbove).toBe(25)
  })
})

// ─── DiscountUpdateSchema ────────────────────────────────────────────────────

describe('DiscountUpdateSchema', () => {
  it('accepts partial update', () => {
    const result = DiscountUpdateSchema.parse({ name: 'Updated Name' })
    expect(result.name).toBe('Updated Name')
    expect(result.discountType).toBeUndefined()
  })

  it('accepts empty object (defaults still apply)', () => {
    const result = DiscountUpdateSchema.parse({})
    expect(result.appliesTo).toBe('line_item')
    expect(result.isActive).toBe(true)
    expect(result.name).toBeUndefined()
  })
})

// ─── DrawerOpenSchema ────────────────────────────────────────────────────────

describe('DrawerOpenSchema', () => {
  it('parses valid drawer open', () => {
    const result = DrawerOpenSchema.parse({
      locationId: '10000000-1000-4000-8000-000000000001',
      openingBalance: 200,
    })
    expect(result.openingBalance).toBe(200)
  })

  it('allows opening without location (floating drawer)', () => {
    const result = DrawerOpenSchema.parse({ openingBalance: 100 })
    expect(result.locationId).toBeUndefined()
  })

  it('rejects negative opening balance', () => {
    expect(() => DrawerOpenSchema.parse({ openingBalance: -50 })).toThrow()
  })

  it('coerces string opening balance', () => {
    const result = DrawerOpenSchema.parse({ openingBalance: '150' })
    expect(result.openingBalance).toBe(150)
  })
})

// ─── DrawerCloseSchema ───────────────────────────────────────────────────────

describe('DrawerCloseSchema', () => {
  it('parses valid drawer close', () => {
    const result = DrawerCloseSchema.parse({ closingBalance: 250 })
    expect(result.closingBalance).toBe(250)
  })

  it('accepts denominations', () => {
    const result = DrawerCloseSchema.parse({
      closingBalance: 100,
      denominations: { ones: 20, fives: 10, tens: 3 },
    })
    expect(result.denominations!.ones).toBe(20)
  })

  it('accepts notes', () => {
    const result = DrawerCloseSchema.parse({ closingBalance: 100, notes: 'Short $5' })
    expect(result.notes).toBe('Short $5')
  })

  it('coerces empty notes to undefined', () => {
    const result = DrawerCloseSchema.parse({ closingBalance: 100, notes: '' })
    expect(result.notes).toBeUndefined()
  })

  it('rejects negative closing balance', () => {
    expect(() => DrawerCloseSchema.parse({ closingBalance: -10 })).toThrow()
  })
})
