import { describe, it, expect } from 'vitest'
import { matchService } from '../matchService'

describe('matchService', () => {
  describe('getAll', () => {
    it('returns a ListResponse with match data', async () => {
      const result = await matchService.getAll()
      expect(Array.isArray(result.data)).toBe(true)
      expect(result.data.length).toBeGreaterThan(0)
      expect(result.meta!.total).toBe(result.data.length)
    })

    it('each match has required fields', async () => {
      const { data } = await matchService.getAll()
      for (const m of data) {
        expect(typeof m.id).toBe('string')
        expect(typeof m.needId).toBe('string')
        expect(typeof m.propertyId).toBe('string')
        expect(typeof m.matchScore).toBe('number')
        expect(m.matchScore).toBeGreaterThanOrEqual(0)
        expect(m.matchScore).toBeLessThanOrEqual(100)
      }
    })
  })

  describe('getById', () => {
    it('returns a match for an existing id', async () => {
      const { data: all } = await matchService.getAll()
      const id = all[0].id
      const result = await matchService.getById(id)
      expect(result.data?.id).toBe(id)
    })

    it('returns null for an unknown id', async () => {
      const result = await matchService.getById('no-such-match')
      expect(result.data).toBeNull()
    })
  })

  describe('getByNeed', () => {
    it('returns only matches for the given needId', async () => {
      const { data: all } = await matchService.getAll()
      const needId = all[0].needId
      const result = await matchService.getByNeed(needId)
      expect(result.data.every(m => m.needId === needId)).toBe(true)
    })
  })

  describe('getByProperty', () => {
    it('returns only matches for the given propertyId', async () => {
      const { data: all } = await matchService.getAll()
      const propertyId = all[0].propertyId
      const result = await matchService.getByProperty(propertyId)
      expect(result.data.every(m => m.propertyId === propertyId)).toBe(true)
    })
  })

  describe('getScoreBreakdown', () => {
    it('returns a ScoreBreakdown for a valid match', async () => {
      const { data: all } = await matchService.getAll()
      const matchWithBreakdown = all.find(m => !!m.scoreBreakdown)
      if (!matchWithBreakdown) return // seed data may not always have breakdowns
      const result = await matchService.getScoreBreakdown(matchWithBreakdown.id)
      expect(result.data).not.toBeNull()
    })

    it('returns null for an unknown match', async () => {
      const result = await matchService.getScoreBreakdown('no-such-match')
      expect(result.data).toBeNull()
    })
  })

  describe('computeMatchesForNeed', () => {
    it('returns computed matches for a valid needId', async () => {
      const result = await matchService.computeMatchesForNeed('need-001')
      expect(result.data.length).toBeGreaterThan(0)
      expect(result.data.every(m => m.needId === 'need-001')).toBe(true)
    })

    it('returns empty array for unknown needId', async () => {
      const result = await matchService.computeMatchesForNeed('no-such-need')
      expect(result.data).toEqual([])
    })
  })

  describe('getStrongMatches', () => {
    it('returns only matches at or above the threshold', async () => {
      const minScore = 70
      const result = await matchService.getStrongMatches(minScore)
      expect(result.every(m => m.matchScore >= minScore)).toBe(true)
    })

    it('returns at most 5 items', async () => {
      const result = await matchService.getStrongMatches(0)
      expect(result.length).toBeLessThanOrEqual(5)
    })

    it('each item has propertyTitle and topReason', async () => {
      const result = await matchService.getStrongMatches(0)
      for (const item of result) {
        expect(typeof item.propertyTitle).toBe('string')
        expect(typeof item.topReason).toBe('string')
        expect(typeof item.matchScore).toBe('number')
      }
    })
  })
})
