/-
Copyright (c) 2024 Joseph Tooby-Smith. All rights reserved.
Released under Apache 2.0 license.
Authors: Joseph Tooby-Smith
-/
import Batteries.Lean.HashSet
import Lean
import Mathlib.Lean.Expr.Basic
import Mathlib.Lean.CoreM
import HepLean
/-!

# HepLean Stats

This file concerns with statistics of HepLean.

-/


open Lean System Meta

structure FileStats where
  numDefs : Nat
  numLemsWithoutDocString : Nat
  numLemsWithDocString : Nat

def FileStats.add (a b : FileStats) : FileStats where
  numDefs := a.numDefs + b.numDefs
  numLemsWithoutDocString := a.numLemsWithoutDocString + b.numLemsWithoutDocString
  numLemsWithDocString := a.numLemsWithDocString + b.numLemsWithDocString

def FileStats.zero : FileStats where
  numDefs := 0
  numLemsWithoutDocString := 0
  numLemsWithDocString := 0

instance : ToString FileStats where
  toString fs := s!"Number of definitions: {fs.numDefs}\n" ++
    s!"Number of lemmas without doc string: {fs.numLemsWithoutDocString}\n" ++
    s!"Number of lemmas with doc string: {fs.numLemsWithDocString}"

def getConstantDoc (constName : Array ConstantInfo) : MetaM (FileStats) := do
  let env ← getEnv
  let mut numDefs := 0
  let mut numLemsWithoutDocString := 0
  let mut numLemsWithDocString := 0
  for c in constName do
    if ¬ Lean.Name.isInternalDetail c.name then
      if c.isDef then
        numDefs := numDefs + 1
      if c.isThm then
        let doc ← Lean.findDocString? env c.name
        if doc == none then
          numLemsWithoutDocString := numLemsWithoutDocString + 1
        else
          numLemsWithDocString := numLemsWithDocString + 1
  return {numDefs := numDefs,
          numLemsWithoutDocString := numLemsWithoutDocString,
          numLemsWithDocString := numLemsWithDocString}

def getStats (imp : Import) : MetaM FileStats := do
  if imp.module == `Init then
    return {numDefs := 0,
            numLemsWithoutDocString := 0,
            numLemsWithDocString := 0}
  let mFile ← findOLean imp.module
  let (modData, _) ← readModuleData mFile
  let cons := modData.constants
  let out ← (getConstantDoc cons)
  return out

def getStatsArray (a : Array Import) : MetaM (Array FileStats) := do
  return ← a.mapM getStats

def main (_ : List String) : IO UInt32 := do
  initSearchPath (← findSysroot)
  let mods : Name :=  `HepLean
  let imp :  Import := {module := mods}
  let mFile ← findOLean imp.module
  unless (← mFile.pathExists) do
        throw <| IO.userError s!"object file '{mFile}' of module {imp.module} does not exist"
  let (hepLeanMod, _) ← readModuleData mFile
  let noFiles := hepLeanMod.imports.size - 1
  let fileStats ← CoreM.withImportModules #[`HepLean] (getStatsArray hepLeanMod.imports).run'
  let totalStats := Array.foldl FileStats.add FileStats.zero fileStats
  IO.println s!"Total number of files: {noFiles}"
  IO.println totalStats
  pure 0
