import { describe, it, expect } from 'vitest'
import { matchStrengthFromScore, rankMatches, buildFullMatch } from '../rankingEngine'
import { MatchStrength, ResultType } from '../../../domain/enums'
import { makeNeed, makeProperty } from './fixtures'

// ── matchStrengthFromScore ────────────────────────────────────────────────────

describe('matchStrengthFromScore', () => {
  it('classifies score >= 78 as STRONG', () => {
    expect(matchStrengthFromScore(78)).toBe(MatchStrength.STRONG)
    expect(matchStrengthFromScore(100)).toBe(MatchStrength.STRONG)
    expect(matchStrengthFromScore(90)).toBe(MatchStrength.STRONG)
  })

  it('classifies score 52–77 as MODERATE', () => {
    expect(matchStrengthFromScore(77)).toBe(MatchStrength.MODERATE)
    expect(matchStrengthFromScore(52)).toBe(MatchStrength.MODERATE)
    expect(matchStrengthFromScore(65)).toBe(MatchStrength.MODERATE)
  })

  it('classifies score < 52 as WEAK', () => {
    expect(matchStrengthFromScore(51)).toBe(MatchStrength.WEAK)
    expect(matchStrengthFromScore(0)).toBe(MatchStrength.WEAK)
    expect(matchStrengthFromScore(30)).toBe(MatchStrength.WEAK)
  })
})

// ── rankMatches ───────────────────────────────────────────────────────────────

describe('rankMatches', () => {
  const need = makeNeed()

  it('sorts matches by matchScore descending', () => {
    const high = buildFullMatch(need, makeProperty({ id: 'high', rentPricePerSqm: 40 }))
    const low  = buildFullMatch(need, makeProperty({ id: 'low', rentPricePerSqm: 65, location: { city: 'Basel', country: 'CH' } }))
    const ranked = rankMatches([low, high])
    expect(ranked[0].matchScore).toBeGreaterThanOrEqual(ranked[1].matchScore)
    expect(ranked[0].propertyId).toBe('high')
  })

  it('breaks ties by result type: VERIFIED_PORTFOLIO and MAISON_WORK ranked above FUTURE_AVAILABILITY', () => {
    // Build one of each type but force identical score by using same property body
    const prop = makeProperty()
    const verified  = buildFullMatch(need, { ...prop, id: 'v', resultType: ResultType.VERIFIED_PORTFOLIO })
    const future    = buildFullMatch(need, { ...prop, id: 'f', resultType: ResultType.FUTURE_AVAILABILITY, confidenceScore: 0.85 })

    // Force same score for a clean tiebreak test
    verified.matchScore = 75
    future.matchScore   = 75

    const ranked = rankMatches([future, verified])
    expect(ranked[0].resultType).toBe(ResultType.VERIFIED_PORTFOLIO)
  })

  it('breaks ties among same type by confidence descending', () => {
    const highConf = buildFullMatch(need, makeProperty({ id: 'hc', confidenceScore: 0.90 }))
    const lowConf  = buildFullMatch(need, makeProperty({ id: 'lc', confidenceScore: 0.60 }))

    // Force same score and same type
    highConf.matchScore = 75
    lowConf.matchScore  = 75

    const ranked = rankMatches([lowConf, highConf])
    expect(ranked[0].confidenceLevel).toBeGreaterThan(ranked[1].confidenceLevel)
  })
})

// ── buildFullMatch ────────────────────────────────────────────────────────────

describe('buildFullMatch', () => {
  it('returns a Match with all required explainability fields', () => {
    const match = buildFullMatch(makeNeed(), makeProperty())
    expect(match.id).toContain('match-')
    expect(match.scoreBreakdown).toBeDefined()
    expect(match.scoreBreakdown.hardMatchScore).toBeGreaterThan(0)
    expect(match.scoreBreakdown.softFactorScore).toBeGreaterThan(0)
    expect(match.scoreBreakdown.totalScore).toBe(match.matchScore)
    expect(match.matchStrength).toBeDefined()
    expect(match.explainabilitySummary).toBeTruthy()
  })

  it('generates shortlist and contact actions for a strong match', () => {
    const match = buildFullMatch(makeNeed(), makeProperty())
    // Perfect fixture should score >= 78 (STRONG) and generate SHORTLIST + CONTACT actions
    if (match.matchScore >= 78) {
      const types = match.nextBestActions?.map(a => a.actionType) ?? []
      expect(types).toContain('SHORTLIST')
      expect(types).toContain('CONTACT')
    }
  })

  it('adds a SCHEDULE action for future availability properties', () => {
    const prop = makeProperty({ resultType: ResultType.FUTURE_AVAILABILITY })
    const match = buildFullMatch(makeNeed(), prop)
    const types = match.nextBestActions?.map(a => a.actionType) ?? []
    expect(types).toContain('SCHEDULE')
  })

  it('uncertainty indicators include a note for future availability', () => {
    const prop = makeProperty({ resultType: ResultType.FUTURE_AVAILABILITY })
    const match = buildFullMatch(makeNeed(), prop)
    expect(match.uncertaintyIndicators?.some(s => s.includes('Signal'))).toBe(true)
  })
})
