import mongoose, { Document, Model, PopulatedDoc } from "mongoose";
import SequenceFactory from "mongoose-sequence";
import bcrypt from "bcryptjs";
import md5 from "blueimp-md5";
import jwt from "jsonwebtoken";
import { hasMigrated } from "@dbconfig";
import { IBand } from "./band";
import { IStory } from "./stories/index";
import { QuickMenuItem, QuickMenuSchema } from "./quickMenu";
// import { FilterPick, PopulatedDocKeys, PopulatedPick } from "~/utils/filter";

const AutoIncrement = SequenceFactory(mongoose);
interface IIPLogEntry {
	lastAccess: Date;
	ip: string;
}

export interface IUser extends Document {
	_id?: number;
	username: string;
	email: string;
	password: string;
	auth: {
		emailVerified: boolean;
		activationKey: string | null;
		passwordResetToken: string | null;
	};
	ts: {
		created: Date;
		updated: Date;
	};
	ipLog: IIPLogEntry[];
	lastLogin: Date;
	lastVisit: Date;
	profile: {
		avatar?: string;
		isAdmin: boolean;
		nightMode: boolean;
		bio: string;
		location: string;
		occupation: string;
		website: string;
		blog: string;
		views: number;
		lastWhere: string | null;
		hidden: boolean;
		disclaimer: string;
		showEmail: boolean;
	};
	biffno: {
		years: string[];
		wins: number;
	};
	favs: {
		authors: PopulatedDoc<IUser & Document>[];
		stories: PopulatedDoc<IStory & Document>[];
	};
	subscriptions: {
		authors: PopulatedDoc<IUser & Document>[];
		bands: PopulatedDoc<IBand & Document>[];
		stories: PopulatedDoc<IStory & Document>[];
	};
	//@ts-ignore SHUT UP
	hiddenAuthors: PopulatedDoc<IUser & Document>[];
	hiddenBands: PopulatedDoc<IBand & Document>[];
	//@ts-ignore SHUT UP
	blocked: PopulatedDoc<IUser & Document>[];
	sessionId: string | null;
	banned: boolean;
	quickMenuConfig: QuickMenuItem[];
	notifyOnReviewReply?: boolean;
	validPassword(password: string): boolean;
	generateRefreshToken(jwtSecret: string): string;
	generateAccessToken(jwtSecret: string): string;
}
// type iut = IUser;
interface UModel extends Model<IUser> {
	generateHash(pwd: string): string;
}

const UserSchema = new mongoose.Schema<IUser>({
	_id: {
		type: Number,
	},
	username: {
		type: String,
	},
	email: {
		type: String,
	},
	password: {
		type: String,
	},
	auth: {
		emailVerified: {
			type: Boolean,
			default: false,
		},
		activationKey: {
			type: String,
		},
		passwordResetToken: {
			type: String,
			default: null,
		},
	},
	ts: {
		created: {
			type: Date,
			default: new Date(),
		},
		updated: {
			type: Date,
			default: new Date(),
		},
	},
	ipLog: [
		{
			ip: {
				type: String,
			},
			lastAccess: {
				type: Date,
				default: new Date(),
			},
		},
	],
	lastLogin: {
		type: Date,
		default: null,
	},
	lastVisit: {
		type: Date,
		default: null,
	},
	profile: {
		avatar: {
			type: String,
			default: "",
		},
		isAdmin: {
			type: Boolean,
			default: false,
		},
		nightMode: {
			type: Boolean,
			default: false,
		},
		bio: {
			type: String,
			default: "",
		},
		location: {
			type: String,
			default: "",
		},
		occupation: {
			type: String,
			default: "",
		},
		website: {
			type: String,
			default: "",
		},
		blog: {
			type: String,
			default: "",
		},
		views: {
			type: Number,
			min: 0,
			default: 0,
		},
		lastWhere: {
			type: String,
			default: null,
		},
		hidden: {
			type: Boolean,
			default: false,
		},
		disclaimer: {
			type: String,
			default: "",
		},
		showEmail: {
			type: Boolean,
			default: false,
		},
	},
	biffno: {
		years: [
			{
				type: String,
			},
		],
		wins: {
			type: Number,
			default: 0,
		},
	},
	favs: {
		authors: [
			{
				type: Number,
				ref: "User",
			},
		],
		stories: [
			{
				type: Number,
				ref: "Story",
			},
		],
	},
	subscriptions: {
		authors: [
			{
				type: Number,
				ref: "User",
			},
		],
		stories: [
			{
				type: Number,
				ref: "Story",
			},
		],
		bands: [
			{
				type: Number,
				ref: "Band",
			},
		],
	},
	hiddenBands: [
		{
			type: Number,
			ref: "Band",
		},
	],
	hiddenAuthors: [
		{
			type: Number,
			ref: "User",
		},
	],
	notifyOnReviewReply: {
		type: Boolean,
		default: true,
	},
	blocked: [
		{
			type: Number,
			ref: "User",
		},
	],
	sessionId: {
		type: String,
		default: null,
	},
	banned: {
		type: Boolean,
		default: false,
	},
	quickMenuConfig: [QuickMenuSchema],
});

UserSchema.static("generateHash", function (password: string): string {
	return bcrypt.hashSync(password, bcrypt.genSaltSync(8));
});
UserSchema.methods.validPassword = function (password: string): boolean {
	return md5(password) === this.password || bcrypt.compareSync(password, this.password) || false;
};

UserSchema.methods.generateRefreshToken = function (jwtKey: string): string {
	return jwt.sign({ id: this._id, isAdmin: this.profile.isAdmin }, jwtKey, {
		expiresIn: "1h",
	});
};

UserSchema.methods.generateAccessToken = function (jwtKey: string): string {
	return jwt.sign({ id: this._id, isAdmin: this.profile.isAdmin }, jwtKey, {
		expiresIn: "16m",
	});
};

hasMigrated && !mongoose.models.User && UserSchema.plugin(AutoIncrement, { id: "userid", inc_field: "_id" });
export const User = mongoose.model<IUser, UModel>("User", UserSchema, "users");