import test from "ava";
import { SCHEMA, Model } from "../../lib/ormish.js";
// TODO: make a clean test that doesn't need user
// TODO: use a :memory: sqlite to do the tests
import { User } from "../../lib/models.js";
import {random_user} from "../../lib/testing.js";


class Migration extends Model.from_table('knex_migrations') {
}

test("confirm schema is loaded", (t) => {
  t.not(SCHEMA, undefined);
  t.not(SCHEMA["knex_migrations"], undefined);

  const mig = new Migration({});
  t.not(mig.schema, undefined);
  t.is(mig.schema, SCHEMA["knex_migrations"]._columns);
});

test('test the validation generation', (t) => {
  const rules = User.validation({
    email: "",
    initials: "",
    full_name: "",
    password: "",
    password_repeat: 'required_with:password|same:password',
  });

  t.is(rules.email, "required|email|min:0|max:255");
  t.is(rules.initials, "required|string|min:0|max:255");
  t.is(rules.password_repeat, 'required_with:password|same:password');
});

test("test that clean and from work", (t) => {
  let user = random_user();
  user.bad_key = "NOPE";
  user.another = "GOODBYE";

  let tester = User.from(user);

  t.is(tester.bad_key, undefined);
  t.is(tester.another, undefined);

  user.bad_key = "NOPE";
  user.another = "GOODBYE";

  user = User.clean(user);
  t.is(user.bad_key, undefined);
  t.is(user.another, undefined);
});

test("basic crud operations on user", async (t) => {
  // use from to confirm they match after insert
  const user = random_user();
  // NOTE: this won't do the correct registration process

  // insert creates a record
  let u2 = await User.insert(user);
  t.not(u2, undefined);
  t.is(u2.email, user.email);

  // first but get all
  let u3 = await User.first({id: u2.id});
  t.not(u3, undefined);
  t.is(u3.email, u2.email);
  t.is(u3.id, u2.id);

  // first but only email column
  let u4 = await User.first({id: u3.id}, ["email"]);
  t.not(u4, undefined);
  t.is(u4.email, u3.email);
  t.is(u4.initials, undefined); // yes, undefined

  // first fails
  let u5 = await User.first({email: "does not exist"});
  t.is(u5, undefined);

  // exists
  t.is(await User.exists({email: u3.email}), u3.id);
  t.is(await User.exists({email: "does not"}), false); // yes, undefined

  // all, using a where func
  let all = await User.all((q) => {
    q.where("id", ">", 10);
  });

  t.not(all, undefined);
  t.not(all.length, 0);

  // all with where and columns
  all = await User.all(q => {
    q.where("id", ">", 10);
  }, ["email"]);

  t.not(all, undefined);
  t.not(all.length, 0);
  t.not(all[0].email, undefined);

  // count with where func
  let count = await User.count(q => {
    q.where("id", ">", 10);
  });

  t.is(count, all.length);

  // all fails
  all = await User.all({email: "does not"}, ["email"]);
  t.is(all.length, 0);

  // delete
  t.is(await User.delete({id: u3.id}), 1);
  // delete nothing
  t.is(await User.delete({email: "does not"}), 0);
});



test("upsert works in all situations", async(t) => {
  let up1 = random_user();

  try {
    // attempt upsert that will insert
    let res = await User.upsert(up1, "email");
    t.not(res, undefined);

    let up2 = await User.first({email: up1.email});
    t.is(up1.email, up2.email);

    // attempt upsert that will ignore
    delete up2.id;
    up2.initials = "TST";

    let up3 = await User.upsert(up2, "email", false);

    let up4 = await User.first({id: up3});
    t.is(up4.email, up2.email);
    t.not(up4.initials, up2.initials);
  } catch(error) {
    console.error(error);
  } finally {
    if(up1) await User.delete({email: up1.email});
  }
});
