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

// These tests pin the rules-based prose checker's behavior. For an ESL writer a
// *wrong* nudge costs trust faster than a missed one earns it, so every rule is
// tested in two directions: a true-positive case that must fire, and at least
// one near-miss "guard" case that must stay silent. Sentences are padded past
// the 8-word floor that analyzeProse needs before it offers advice.

const rulesFor = (text: string) => analyzeProse(text).map((h) => h.rule)

// Assert a given rule appears among the hints for this text.
function expectRule(text: string, rule: string) {
  expect(rulesFor(text), `expected "${rule}" for: ${text}`).toContain(rule)
}

// Assert the text produces no hints at all (false-positive guard).
function expectClean(text: string) {
  expect(analyzeProse(text), `expected no hints for: ${text}`).toEqual([])
}

describe('analyzeProse — floor', () => {
  it('stays quiet on very short drafts (under 8 English words)', () => {
    expect(analyzeProse('he go now')).toEqual([])
  })

  it('returns hints highest-priority first', () => {
    // This 36-word run-on also contains a lowercase "i"; run-on must lead.
    const hints = analyzeProse(
      'yesterday i walked all the way to the market and i bought apples and oranges and i saw my friend there and we talked and laughed and walked back home together in the warm afternoon sun.',
    )
    expect(hints[0].rule).toBe('runon')
    expect(hints.map((h) => h.rule)).toContain('cap-i')
  })
})

describe('run-ons', () => {
  it('flags a long, comma-heavy sentence', () => {
    expectRule(
      'I went to the market and I bought some apples and then I saw my friend and we talked for a while and after that we went to the cafe and ordered coffee and cake together.',
      'runon',
    )
  })

  it('leaves a normal sentence alone', () => {
    expectClean('The garden was quiet in the morning and the rain fell softly on the leaves.')
  })
})

describe('comma splices', () => {
  it('flags two independent clauses joined by a comma', () => {
    expectRule('I finished the report, I sent it to my boss right away today.', 'splice')
  })

  it('catches a splice with a verb not on any list', () => {
    expectRule('The garden was quiet in the morning, she poured a cup of tea slowly.', 'splice')
  })

  it('does not flag an introductory transition (However, …)', () => {
    expectClean('However, we decided to stay home and rest for the entire weekend.')
  })

  it('does not flag an introductory phrase (After dinner, …)', () => {
    expectClean('After dinner, I went home and read a book until I fell asleep.')
  })

  it('does not flag a pronoun list after a comma', () => {
    expectClean('We invited my brother, you and your sister to the dinner party.')
  })
})

describe('unclear antecedents', () => {
  it('flags a vague "This + verb" opener after a prior sentence', () => {
    expectRule(
      'We changed the whole schedule last week. This makes everyone confused about the new times.',
      'antecedent',
    )
  })

  it('leaves "This" alone when it names its noun', () => {
    expectClean(
      'We changed the whole schedule last week. This new schedule confuses everyone about the times.',
    )
  })
})

describe('oxford comma', () => {
  it('flags a 3-item noun list missing the serial comma', () => {
    expectRule('My mother, my father and my sister came to visit us last summer.', 'oxford')
  })

  it('flags a verb-phrase list missing the serial comma', () => {
    expectRule('We cleaned the kitchen, washed the dishes and took out the trash.', 'oxford')
  })

  it('does not flag a list that already has the serial comma', () => {
    expectClean('I bought apples, bananas, and oranges at the store this morning.')
  })

  it('does not flag a compound predicate as a list', () => {
    expectClean('After dinner, I went home and read a book until I fell asleep.')
  })
})

describe('a / an', () => {
  it('flags "a" before a vowel sound', () => {
    expectRule('She found a umbrella and a old book on the table by the window.', 'article')
  })

  it('flags "an" before a consonant sound', () => {
    expectRule('He gave me an book and an pencil to use during the long exam.', 'article')
  })

  it('respects sound exceptions (a university, an hour)', () => {
    expectClean('He is a university student and it took an hour to arrive here.')
  })
})

describe('uncountable plurals', () => {
  it('flags a pluralized mass noun', () => {
    expectRule('She gave me many informations about the new job opening today.', 'uncountable')
  })

  it('leaves the singular mass noun alone', () => {
    expectClean('He shared some useful advice and helped me with my homework tonight.')
  })
})

describe('capitalization of proper nouns', () => {
  it('flags lowercase languages and days', () => {
    expectRule('I am learning english and french during my free time every week.', 'propercap')
    expectRule('We will meet on monday to discuss the final project together soon.', 'propercap')
  })

  it('does not flag ambiguous homographs (may, march)', () => {
    expectClean('They may visit in the spring and march through the old town square.')
  })

  it('leaves already-capitalized proper nouns alone', () => {
    expectClean('I will study English and Chinese together this coming summer break here.')
  })
})

describe('subject–verb agreement', () => {
  it('flags a bare verb after he/she/it', () => {
    expectRule('My brother is busy but he go to the gym every single morning.', 'sva')
    expectRule('She have a lovely garden full of roses behind her small house.', 'sva')
  })

  it('flags a sentence-initial subject too', () => {
    expectRule('It make me happy whenever the sun comes out after the rain.', 'sva')
  })

  it('does not flag causative/perception frames (let it go, make it work)', () => {
    expectClean('Please let it go and try to enjoy the rest of your day.')
    expectClean('We should make it work before the big meeting tomorrow afternoon.')
  })
})

describe('plural after a number', () => {
  it('flags a singular noun after a cardinal number', () => {
    expectRule('I bought three apple and some bread at the market this morning.', 'plural')
  })

  it('does not flag an adjective between number and noun', () => {
    expectClean('We adopted two small dogs from the shelter near our apartment today.')
  })

  it('does not flag irregular plurals (five people)', () => {
    expectClean('There were five people waiting patiently outside in the cold morning rain.')
  })

  it('does not flag an already-plural noun', () => {
    expectClean('She has two cats and they sleep all day long on the couch.')
  })
})

describe('double determiner', () => {
  it('flags a stacked article + possessive', () => {
    expectRule('Please put the my book back on the shelf when you finish it.', 'doubledet')
  })
})

describe('there is + plural', () => {
  it('flags "there is" with a plural quantifier', () => {
    expectRule('There is many reasons to visit the coast during the warm months.', 'thereis')
  })

  it('does not flag "there is some" with a mass noun', () => {
    expectClean('There is some water left in the bottle if you are thirsty now.')
  })
})

describe('its / it’s', () => {
  it("flags it's used as a possessive", () => {
    expectRule("The cat licked it's own paw while sitting quietly by the window.", 'its')
  })

  it('flags its used where "it is" is meant', () => {
    expectRule('I think its a wonderful idea to travel together next year sometime.', 'its')
  })

  it('leaves correct possessive "its" alone', () => {
    expectClean('The dog wagged its tail happily when we came home that evening.')
  })
})

describe('than / then', () => {
  it('flags a comparative followed by "then"', () => {
    expectRule('This cake tastes much better then the one we made last weekend.', 'than')
  })

  it('leaves sequential "then" alone', () => {
    expectClean('We ate dinner and then we watched a long movie on the sofa.')
  })
})

describe('comma after a transition', () => {
  it('flags a sentence-initial transition with no comma', () => {
    expectRule('However we decided to stay home and rest for the whole weekend.', 'introcomma')
  })

  it('does not flag a sequence word (Then …)', () => {
    expectClean('Then we walked to the park and fed the ducks by the pond.')
  })
})

describe('spacing around punctuation', () => {
  it('flags a missing space after a comma', () => {
    expectRule('I like apples,bananas and grapes from the little shop down the street.', 'space-after')
  })

  it('flags a space before punctuation', () => {
    expectRule('She smiled warmly , then walked away without saying a single word today.', 'space-punct')
  })

  it('does not flag thousands separators in numbers', () => {
    expectClean('The list had 1,000 items and cost us about 2,500 dollars in total.')
  })
})

describe('capitalization basics', () => {
  it('flags a lowercase standalone "i"', () => {
    expectRule('Yesterday i walked to the store and bought milk, eggs, and bread.', 'cap-i')
  })

  it('flags a sentence that does not start with a capital', () => {
    expectRule('The sun set slowly. it was a beautiful evening down by the river.', 'cap-sentence')
  })
})
