open Lacaml.D
open Util

type guess = 
| Hcore  of Mat.t
| Huckel of Mat.t
| Matrix of Mat.t

type t = guess

module Ao = AOBasis
module El = Electrons
module Ov = Overlap

let hcore_guess ao_basis = 
  let eN_ints  = Ao.eN_ints  ao_basis |> NucInt.matrix
  and kin_ints = Ao.kin_ints ao_basis |> KinInt.matrix
  in
  Mat.add eN_ints kin_ints


let huckel_guess ao_basis =
  let c = 0.5 *. 1.75 in
  let eN_ints  = Ao.eN_ints  ao_basis |> NucInt.matrix
  and kin_ints = Ao.kin_ints ao_basis |> KinInt.matrix
  in
  let m_F = 
    Mat.add eN_ints kin_ints
  in
  let ao_num   = Ao.basis    ao_basis |> Basis.size 
  and overlap  = Ao.overlap  ao_basis |> Ov.matrix
  in
  let diag = Vec.init ao_num (fun i -> 
    m_F.{i,i} )
  in

  function 
  | 0 -> invalid_arg "Huckel guess needs a non-zero number of occupied MOs."
  | nocc -> 
    Mat.init_cols ao_num ao_num (fun i j ->
        if (i<>j) then
          if (diag.{i} +. diag.{j}) < 0. then
            c *. overlap.{i,j} *. (diag.{i} +. diag.{j}) +. m_F.{i,j} (*TODO Pseudo *)
          else
            m_F.{i,j} (*TODO Pseudo *)
        else
          diag.{i}
    )


let make ?(nocc=0) ~guess ao_basis = 
  match guess with
  | `Hcore  -> Hcore  (hcore_guess  ao_basis)
  | `Huckel -> Huckel (huckel_guess ao_basis nocc)
  | `Matrix m -> Matrix m



let test_case ao_basis =

  let test_hcore () =
    match make ~guess:`Hcore ao_basis with
    | Hcore matrix -> 
      let a = Lacaml.D.Mat.to_array matrix in
      let reference =
        Lacaml.D.Mat.add 
          (AOBasis.eN_ints  ao_basis |> NucInt.matrix)
          (AOBasis.kin_ints ao_basis |> KinInt.matrix)
        |> Lacaml.D.Mat.to_array
      in
      Array.iteri (fun i x ->
        let message =
          Printf.sprintf "Guess line %d" (i)
        in
        Alcotest.(check (array (float 1.e-15))) message a.(i) x) reference
    | _ -> assert false
  
  in
  [
    "HCore", `Quick, test_hcore;
  ]

