import mongoose, { Schema, connect, PopulatedDoc, Document, Model } from "mongoose";
import SequenceFactory from "mongoose-sequence";
import bcrypt from "bcryptjs";
import md5 from "blueimp-md5";
import jwt from "jsonwebtoken"
import { hasMigrated } from "../lib/dbconfig";
import { IBand } from "./band";
import {IStory} from "./stories/index"
import { QuickMenuItem, QuickMenuSchema } from "./quickMenu";

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[]
	validPassword(password: string): boolean;
	generateToken(jwtSecret: string): string;
}
// type iut = IUser;
interface UModel extends Model<IUser> {
	generateHash(pwd: string): string;
}

const UserSchema = new mongoose.Schema<IUser, UModel>({
	_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"
	}],
	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.generateToken = function(jwtKey: string): string {
	let token = jwt.sign({id: this._id, isAdmin: this.profile.isAdmin}, jwtKey, {
		expiresIn: '14 days'
	})
	return token
}

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