import Mathlib.GroupTheory.Subgroup.Basic
-- import Mathlib.GroupTheory.Commutator
-- import Mathlib.GroupTheory.GroupAction.Basic
-- import Mathlib.GroupTheory.Exponent
-- import Mathlib.GroupTheory.Perm.Basic

import Lean.Meta.Tactic.Util
import Lean.Elab.Tactic.Basic
import Lean.Meta.Tactic.Simp.Main
import Mathlib.Tactic.Ring.Basic
import Mathlib.Tactic.FailIfNoProgress
import Mathlib.Tactic.Group

namespace Rubin.Tactic

open Lean.Parser.Tactic

--@[simp]
theorem smul_eq_smul_inv {G α : Type _} [Group G] [MulAction G α] {g h : G}
    {x y : α} : g • x = h • y ↔ (h⁻¹ * g) • x = y :=
  by
  constructor
  · intro hyp
    let res := congr_arg ((· • ·) h⁻¹) hyp
    simp at res
    rw [← mul_smul] at res
    exact res
  · intro hyp
    rw [<-hyp, mul_smul]
    simp
#align smul_eq_smul Rubin.Tactic.smul_eq_smul_inv

theorem smul_succ {G α : Type _} (n : ℕ) [Group G] [MulAction G α] {g : G}
    {x : α} : g ^ n.succ • x = g • g ^ n • x :=
  by
  rw [pow_succ, mul_smul]
#align smul_succ Rubin.Tactic.smul_succ

-- Note: calling "group" after "group_action₁" might not be a good idea, as they can end up running in a loop
syntax (name := group_action₁) "group_action₁" (location)?: tactic
macro_rules
  | `(tactic| group_action₁ $[at $location]?) => `(tactic| simp (config := {zeta := false}) only [
    smul_smul,
    Rubin.Tactic.smul_eq_smul_inv,
    Rubin.Tactic.smul_succ,

    one_smul,
    mul_one,
    one_mul,
    sub_self,
    add_neg_self,
    neg_add_self,
    neg_neg,
    tsub_self,
    <-mul_assoc,

    one_pow,
    one_zpow,
    <-mul_zpow_neg_one,
    zpow_zero,
    mul_zpow,
    zpow_sub,
    <-zpow_ofNat,
    <-zpow_neg_one,
    <-zpow_mul,
    <-zpow_add_one,
    <-zpow_one_add,
    <-zpow_add,

    Int.ofNat_add,
    Int.ofNat_mul,
    Int.ofNat_zero,
    Int.ofNat_one,
    Int.mul_neg_eq_neg_mul_symm,
    Int.neg_mul_eq_neg_mul_symm,

    Mathlib.Tactic.Group.zpow_trick,
    Mathlib.Tactic.Group.zpow_trick_one,
    Mathlib.Tactic.Group.zpow_trick_one',

    commutatorElement_def
  ] $[at $location]?
)

/-- Tactic for normalizing expressions in group actions, without assuming
commutativity, using only the group axioms without any information about
which group is manipulated.
Example:
```lean
example {G α : Type} [Group G] [MulAction G α] (a b : G) (x y : α) (h : a • b • x = a • y) : b⁻¹ • y = x := by
  group_action at h -- normalizes `h` which becomes `h : c = d`
  rw [←h]           -- the goal is now `a*d*d⁻¹ = a`
  group_action      -- which then normalized and closed
```
-/
syntax (name := group_action) "group_action" (location)?: tactic
macro_rules
  | `(tactic| group_action $[at $location]?) => `(tactic|
    repeat (fail_if_no_progress (group_action₁ $[at $location]? <;> group $[at $location]?))
  )

example {G α: Type _} [Group G] [MulAction G α] (g h: G) (x: α): g • h • x = (g * h) • x := by
  group_action

example {G α : Type} [Group G] [MulAction G α] (a b : G) (x y : α) (h : a • b • x = a • y) : b⁻¹ • y = x := by
  group_action at h  -- normalizes `h` which becomes `h : c = d`
  rw [←h]            -- the goal is now `a*d*d⁻¹ = a`
  group_action       -- which then normalized and closed

example (G α : Type _) [Group G] (a b c : G) [MulAction G α] (x : α) :
    ⁅a * b, c⁆ • x = (a * ⁅b, c⁆ * a⁻¹ * ⁅a, c⁆) • x := by
  group_action

section PotentialLoops

variable {G α : Type _}
variable [Group G]
variable [MulAction G α]
variable (g f : G)
variable (x : α)

example: x = g • f⁻¹ • g⁻¹ • x ↔ g⁻¹ • x = f • g⁻¹ • x := by
  group_action
  constructor <;> intro h <;> exact h.symm

example: x = g • f⁻¹ • g⁻¹ • x ↔ g⁻¹ • x = f • g⁻¹ • x := by
  constructor
  · intro h
    group_action at h
    nth_rewrite 2 [h]
    group_action
  · intro h
    group_action at h
    nth_rewrite 1 [<-h]
    group_action

example: x = g • f⁻¹ • g⁻¹ • x ↔ g⁻¹ • x = f⁻¹ • g⁻¹ • x := by
  constructor
  · intro h
    nth_rewrite 1 [h]
    group_action
  · intro h
    group_action at h
    nth_rewrite 2 [<-h]
    group_action

example (h: (g * f ^ (-2 : ℤ) * g ^ (-1 : ℤ)) • x = x):
  g⁻¹ • (g * f ^ (-1 : ℤ) * g ^ (-1 : ℤ)) • x = f • g⁻¹ • x :=
by
  group_action
  exact h

example (h: x = g • f⁻¹ • g⁻¹ • x): True := by
  group_action at h
  exact True.intro

example (j: ℕ) (h: g • g ^ j • x = x): True := by
  group_action at h
  exact True.intro

example (i: Fin 5) (p : α) (h: f • g ^ i.val • p = g ^ i.val • p): True := by
  group_action at h
  exact True.intro

end PotentialLoops

end Rubin.Tactic
