/-
Author: Nicolas Rouquette with help from Github Copilot with Claude Opus 4.5
Contribution from Vlad Tsyrklevich (vlad902)
Developed with Lean 4.26.0 and Batteries 4.26.0
-/
import Batteries.Data.List.Pairwise
import Batteries.Data.List.Basic

/-!
# Membership lemma for `List.eraseDup`

This file provides `List.mem_eraseDup`, proving that membership is preserved by
`eraseDup` for types with `LawfulBEq`.

## Main Results

* `List.mem_eraseDup`: `a ∈ l.eraseDup ↔ a ∈ l` for `LawfulBEq` types

## Implementation Notes

`eraseDup` is defined as `pwFilter (· != ·)`. The proof uses:
- `pwFilter_subset` for the forward direction
- Induction with `pwFilter_cons_of_pos/neg` for the reverse direction

Unlike `eraseDups` (which uses an accumulator-based loop), `pwFilter` processes
front-to-back keeping elements that are distinct from all later kept elements.
This makes the proof structure inherently different - there's no simple loop
invariant to factor out.

This file is intended for contribution to Batteries. It has no Mathlib dependencies.

## Where this should live

Suggested location: `Batteries/Data/List/Pairwise.lean` or a new file
`Batteries/Data/List/EraseDup.lean` that imports `Pairwise`.
-/

namespace List

/-- Membership is preserved by `eraseDup`: an element is in the deduplicated list
iff it was in the original list. This is the `BEq`/`LawfulBEq` analogue of
Mathlib's `List.mem_dedup` which requires `DecidableEq`. -/
@[simp]
theorem mem_eraseDup [BEq α] [LawfulBEq α] {a : α} {l : List α} :
    a ∈ l.eraseDup ↔ a ∈ l := by
  constructor
  · intro h; exact pwFilter_subset l h
  · intro h
    induction l with
    | nil => exact h
    | cons x xs ih =>
      simp only [mem_cons] at h
      -- Split once: does `x` survive the pwFilter step?
      by_cases hx : ∀ y ∈ xs.eraseDup, (x != y) = true
      · -- x kept: eraseDup (x::xs) = x :: eraseDup xs
        rw [eraseDup, pwFilter_cons_of_pos hx, mem_cons]
        rcases h with rfl | hxs
        · left; rfl
        · right; exact ih hxs
      · -- x dropped: eraseDup (x::xs) = eraseDup xs
        rw [eraseDup, pwFilter_cons_of_neg hx]
        rcases h with rfl | hxs
        · simp_all [eraseDup]  -- extracts witness showing a ∈ xs.eraseDup
        · exact ih hxs

end List
