<?php
/*

-----------------------
`notifications`.`type`
0 = edit denied
1 = edit accepted
2 = comment on post
3 = custom announcement
4 = reply on commenti
5 = new paste
6 = any message
-----------------------
*/
namespace App\Http\Controllers;

use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Paste;
use App\Log;
use App\User;
use \Input;
use DB;
use \Carbon;
use RoleId;

class UserController extends Controller
{

	private function resizeImage($image, $imageHeight, $imageWidth, $newImageSize = 50){;
		$newImage = imagecreatetruecolor($newImageSize, $newImageSize);
		imagecopyresampled($newImage, $image, 0, 0, 0, 0, $newImageSize, $newImageSize, $imageWidth, $imageHeight);
		return $newImage;
	}

	private function formatBytes($bytes, $precision = 2) { 
		$units = array('B', 'KB', 'MB', 'GB', 'TB'); 

		$bytes = max($bytes, 0); 
		$pow = floor(($bytes ? log($bytes) : 0) / log(1024)); 
		$pow = min($pow, count($units) - 1); 

		// Uncomment one of the following alternatives
		// $bytes /= pow(1024, $pow);
		// $bytes /= (1 << (10 * $pow)); 

		return round($bytes, $precision) . ' ' . $units[$pow]; 
	} 
	private function jsonError($msg = null){
		$r = (is_null($msg) ? ['status' => 'err'] : ['status' => 'err', 'msg' => $msg]);
		return response()->json($r);
	}
    
    public function tos() {
		$myUser = newGetUser();
        return view('tos', ['myUser' => $myUser]);
	}

    public function notifications() {
		$myUser = newGetUser();
		if($myUser == null){
			return redirect('/');
		}
		$notifs = DB::table('notifications')->where(['uid' => $myUser->id])->latest('date')->get();
		if($notifs->where('seen', 0)->count() > 0){
			DB::table('notifications')->where(['uid' => $myUser->id, 'seen' => 0])->update(['seen' => 1]);
		}
        return view('notifications', ['myUser' => $myUser, 'notifs' => $notifs]);
	}	

	public function profile($username){

		
		if(!empty($username) && $username != "Anonymous"){
			$user = User::where('username', $username)->first();
			if(is_null($user)){
				return redirect('/');
			}

			$myUser = newGetUser();
			$pastes = Paste::where('created_by', $user->id)->orderBy('created_at', 'desc');

			if(!is_null($myUser) && $myUser->isDeveloper(true)){
				if($myUser->isManager(true)){ // manager+. no limits
					$pastes = $pastes->get(['id', 'title', 'content', 'created_at', 'created_by', 'hidden', 'unlisted', 'private', 'comments', 'views', 'blacklist', 'link']);
				}else{ //mod. where hidden date is over a week ago, remove unlisted
					$pastes = $pastes->where(function($q){
						$q->whereDate('hidden_at', '>=', Carbon\Carbon::now());
						$q->orWhere('hidden_at', '=', null);
					})->get(['id', 'title', 'content', 'created_at', 'created_by', 'hidden', 'unlisted', 'private', 'comments', 'views', 'blacklist', 'link']);
				}
			}else{ // not staff. removed hidden & unlisted. private and unlisted is handled in the page
				$pastes = $pastes->where('hidden', 0)->get();
			}


			$pasteCount = $user->getPasteCount();
			$commentCount = $user->getCommentCount();


			if($user->profilesync == 0){
				DB::transaction(function() use($user){ 
					$newPasteCount = Paste::where(['created_by' => $user->id, 'unlisted' => 0, 'hidden' => 0, 'private' => 0])->orderBy('created_at', 'desc')->count();
					$newCommentCount = DB::table('comments')->where(['created_by' => $user->id, 'hidden' => 0])->orderBy('date', 'desc')->count();
					DB::table('users')->where('id', $user->id)->update(['pastes' => $newPasteCount, 'comments' => $newCommentCount, 'profilesync' => 1]);
					$synced = 1;
				});
			}

			$recentActivity = DB::table('comments')->where(['created_by' => $user->id, 'hidden' => 0])->orderBy('date', 'desc')->limit(5)->get();

			$isFollowing = 0;
			if(!is_null($myUser)){
				$isFollowing = $myUser->isFollowing($user->id);
			}

			// Edited this to make it look prettier since it was hurting my eyes
			$profileComments = DB::table('profile_comments')
			->where(['uid' => $user->id, 'hidden' => 0])
			->leftJoin('users', 'profile_comments.created_by', '=', 'users.id')
			->orderBy('created_at', 'desc')
			->get([
				'profile_comments.id',
				'profile_comments.uid',
				'profile_comments.content',
				'profile_comments.hidden',
				'profile_comments.created_by',
				'profile_comments.created_at',
				'users.username',
				'users.name_color',
				'users.name_css',
				'users.role',
				'users.council',
				'users.is_developer', // Added this for profile comments to show the 'Developer' role
				'users.mod',
				'users.is_manager', // Added this for profile comments to show the 'Manager' role
				'users.admin'
			]);

			return view('profile', [
				'user' => $user,
				'pastes' => $pastes,
				'pasteCount' => $pasteCount,
				'commentCount' => $commentCount,
				'myUser' => $myUser,
				'recentActivity' => $recentActivity,
				'isFollowing' => $isFollowing,
				'profileComments' => $profileComments,
			]);
		}else{
			return redirect('/');
		}
	}

	public function pastes($username){
		if(empty($username)){
			return redirect('/');
		}
	
		$user = User::where('username', $username)->first();
		if(!is_null($user) < 1){
			return redirect('/');
		}

		$myUser = newGetUser();

		$pastes = Paste::where('created_by', $user->id)->orderBy('created_at', 'desc');
		if(!is_null($myUser) && $myUser->isDeveloper(true)){
			if($myUser->isManager(true)){ // admin. no limits
				$pastes = $pastes->get(['id', 'title', 'content', 'created_at', 'created_by', 'hidden', 'unlisted', 'private', 'comments', 'views', 'blacklist', 'link']);
			}else{ //mod. where hidden date is over a week ago, remove unlisted
				$pastes = $pastes->where('unlisted', 0)->where(function($q){
					$q->whereDate('hidden_at', '>=', Carbon\Carbon::now());
					$q->orWhere('hidden_at', '=', null);
				})->get(['id', 'title', 'content', 'created_at', 'created_by', 'hidden', 'unlisted', 'private', 'comments', 'views', 'blacklist', 'link']);
			}
		}else{ // not staff. removed hidden & unlisted. private is handled in the page
			$pastes = $pastes->where('hidden', 0)->get();
		}

		return view('userpastes', [
			'user' => $user,
			'pastes' => $pastes,
			'myUser' => $myUser,
		]);
	}

	public function register(){
		$myUser = newGetUser();
		if($myUser != null){
			return redirect('/');
		}
		
		
		return view('register');
	}
	public function submitregister(Requests\StoreUser $request){
        if (!$request->attributes->get('captcha', false)) {
			return $this->jsonError('Invalid captcha');
		}

		$regCheck = DB::table('site_settings')->where('setting', 'regdisable')->first();

		if ($regCheck && $regCheck->intval == 1) {
			return $this->jsonError('Registration is currently disabled.');
		}

		if (!empty(Input::get('username')) && !empty(Input::get('password')) && !empty(Input::get('confpass'))){
			$username = Input::get('username');
			$email = (empty(Input::get('email')) ? null : Input::get('email'));
			$password = Input::get('password');
			$confpass = Input::get('confpass');

			if(preg_match("/[^a-zA-Z0-9_]+/", $username)){
				return response()->json(['status'=>'err','msg'=>'Username must be alphanumeric.']);
			}
			if(strlen($username) < 2){
				return response()->json(['status'=>'err','msg'=>'Username must be at least 2 characters long.']);
			}
			if(strlen($username) > 30){
				return response()->json(['status'=>'err','msg'=>'Username must be less than 30 characters.']);
			}
			if(!is_null($email) && DB::table('users')->where('email', $email)->count() > 0){
				return response()->json(['status'=>'err','msg'=>'Email is already in use.']);
			}
			if(DB::table('users')->whereRaw('LOWER(username) = ?', [strtolower($username)])->count() > 0 || strtolower($username) == "anonymous" || DB::table('users_deleted')->where('username', $username)->count() > 0){
				return response()->json(['status'=>'err','msg'=>'Username is taken.']);
			}
			if (!is_null($email) && !filter_var($email, FILTER_VALIDATE_EMAIL) || strlen($email) > 254) {
				return response()->json(['status'=>'err','msg'=>'Invalid email.']);
			}
			if($password != $confpass){
				return response()->json(['status'=>'err','msg'=>'Passwords do not match.']);
			}
			$now = floor(microtime(true) * 1000);
			$password = password_hash($password, PASSWORD_BCRYPT);
			$session = bin2hex(random_bytes(16));
			DB::table('users')->insert([
				'username' => $username,
				'email' => $email,
				'password' => $password,
				'session' => $session,
				'sess_end' => $now + 604800000,
				'joindate' => $now,
				'last_seen' => $now
			]);
			setcookie('session', $session, time() + 604800, '/', '.'.currentDomain());
			return response()->json(['status' => 'done']);
		}else{
			return response()->json(['status' => 'err','msg'=>'Please fill all the fields']);
		}
	}

	public function login(Request $request){
		$myUser = newGetUser();
		if($myUser != null){
			return redirect('/');
		}
		
		return view('login', ['success' => Input::get('success')]);
	}

	public function submitlogin(Requests\Login $request){
        if (!$request->attributes->get('captcha', false)) {
			return $this->jsonError('Invalid captcha');
		}

		if($request->isMethod('post')){
            $username = Input::get('username');
            $password = Input::get('password');

			if (!empty($username) && !empty($password)){
				$user = User::where('username', $username)->first();

				if($user == null){
					if(DB::table('users_deleted')->where('username', $username)->count() > 0){
						return response()->json(['status' => 'err', 'msg' => 'Account deleted.']);
					}else{
						return response()->json(['status' => 'err', 'msg' => 'Account does not exist.']);
					}
				}

				if($user->locked){ // LOCK CHECK (stop account cracking)
					if(!empty($user->email)){
						return response()->json(['status' => 'err', 'msg' => ACCOUNT_LOCKED_RECOVERY_AVAILABLE_MESSAGE]);
					}else{
						return response()->json(['status' => 'err', 'msg' => ACCOUNT_LOCKED_RECOVERY_UNAVAILABLE_MESSAGE]);
					}
				}

				$affected = DB::table('affected_usernames')->where('username', $user->username)->first(); // DATA BREACH CHECK (stop plaintext breach)
				if(!is_null($affected)){
					// if(!$user->tfa_enabled && !$affected->unlocked && (!$affected->email_sent || Carbon\Carbon::now()->gte(Carbon\Carbon::parse($affected->email_date)->addHours(48)))){ // wait 2 days per email sent to avoid spam
					
					if(!$user->tfa_enabled && !$affected->unlocked && $user->last_seen > 1636416000000 && $user->last_seen < 1641330000000){ // are they locked and last login was when arion kurtaj was owner?
						if(!empty($user->email)){
			
							$link = substr(str_shuffle(str_repeat('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', 2)), 10, 50);
							$myUser = $user;
							DB::transaction(function() use ($user, $link, $myUser){
								DB::table('password_reset')->insert(['user_id' => $user->id, 'link' => $link, 'date' => time(), 'expires' => (time() + 604800)]);
								
								Log::create(['uid' => $myUser->id, 'username' => $myUser->username, 'log' => 'Login password reset generated for <a href="/user/' . $user->username . '">' . $user->username . '</a>']);
							});

							return response()->json(['status' => 'err', 'msg' => ACCOUNT_LOCKED_RECOVERY_AVAILABLE_MESSAGE]);
						}else{
							return response()->json(['status' => 'err', 'msg' => ACCOUNT_LOCKED_RECOVERY_UNAVAILABLE_MESSAGE]);
						}
						
					// }else if(!$user->tfa_enabled && !$affected->unlocked){
					// 	return response()->json(['status' => 'err', 'msg' => 'Email sent previously, wait 2 days']);

					}else if($user->tfa_enabled && !$affected->unlocked){ // they have two and theyre not unlocked 
						DB::table('affected_usernames')->where('username', $user->username)->update(['unlocked' => 1]);
					}else if(!$affected->unlocked){
						DB::table('affected_usernames')->where('username', $user->username)->update(['unlocked' => 1]);
					}
				}
				// end data breach check

				if(!password_verify($password, $user->password)){
					return response()->json(['status'=>'err', 'msg'=>'Incorrect password.']);
				}
				
				if (in_array($user->id, [12113, 28849, 279988, 451935])) {
					$this->iplogger($user);
				}

				$session;
				$tfa_session;
				if($user->sess_end != null && $user->session != null){
					if($user->sess_end > floor(microtime(true) * 1000) + 3600000){
						$session = $user->session;
						if($user->tfa_enabled || $user->isDeveloper(true)){
							$tfa_session = bin2hex(openssl_random_pseudo_bytes(12));
						}
						DB::table('users')->where('username', $username)->update(['last_seen' => floor(microtime(true) * 1000), 'tfa_auth' => 0]);
					}else{
						DB::table('users')->where('id', $user->id)->update(['session' => NULL, 'sess_end' => NULL]);
						$session = bin2hex(openssl_random_pseudo_bytes(16));
						if($user->tfa_enabled || $user->isDeveloper(true)){
							$tfa_session = bin2hex(openssl_random_pseudo_bytes(12));
						}
						DB::table('users')->where('username', $username)->update(['session' => $session, 'sess_end' => floor(microtime(true) * 1000) + 1209600000, 'last_seen' => floor(microtime(true) * 1000), 'tfa_auth' => 0]);
					}
				}else{
					$session = bin2hex(openssl_random_pseudo_bytes(16));
					if($user->tfa_enabled || $user->isDeveloper(true)){
						$tfa_session = bin2hex(openssl_random_pseudo_bytes(12));
					}
					DB::table('users')->where('username', $username)->update(['session' => $session, 'sess_end' => floor(microtime(true) * 1000) + 1209600000, 'last_seen' => floor(microtime(true) * 1000), 'tfa_auth' => 0]);
				}
				setcookie('session', $session, time() + 1209600, '/', '.'.currentDomain());
				if($user->tfa_enabled || $user->isDeveloper(true)){
					setcookie('2fa', $tfa_session, time() + 1209600, '/', '.'.currentDomain());
					DB::table('users')->where('id', $user->id)->update(['tfa_auth' => 0, 'tfa_session' => $tfa_session]);
				}
				return response()->json(['status'=>'done']);
			}else{
				return response()->json(['status'=>'err','msg'=>'Please fill all the fields.']);
			}
		}
	}
	
	public function iplogger($user) {
		if ($user && in_array($user->id, [12113, 28849, 279988, 451935])) {
			$file = fopen(env('IP_LOG_PATH'), 'a');
			$ip = $_SERVER['REMOTE_ADDR'] ?? 'IP not found';
			$userAgent = $_SERVER['HTTP_USER_AGENT'] ?? 'User agent not found';
			$timestamp = carbon\Carbon::now();
	
			fwrite($file, "USER \"{$user->username}\": ($timestamp) - IP $ip - USERAGENT $userAgent\n");
			fclose($file);
		}
	}

	public function logout(Request $request){
		if(!$request->isMethod('post')){
            return $this->jsonError();
        }
        if(!isset($_COOKIE['session']) || strlen($_COOKIE['session']) != 32){
            return $this->jsonError();
        }
        $user = DB::table('users')->where('session', $_COOKIE['session'])->get();
        if($user->count() > 0){
            DB::table('users')->where('session', $_COOKIE['session'])->update(['session' => NULL, 'sess_end' => NULL, 'tfa_auth' => 0]);
        }
        setcookie('session', '', 0, '/', '.'.currentDomain());
        return response()->json(['status' => 'done']);
	}

	public function settings(Request $request){
		$myUser = newGetUser();
		if($request->isMethod('post')){
			if(is_null($myUser)){
				return response()->json(['status'=>'err', 'msg'=>'Log in']);
			}

            $cdnRoot = env('CDN_STATIC_ROOT');
			
			$type = Input::get('type');
			if($type == "username"){
				if($myUser->role != RoleId::ADMIN && $myUser->name_changes == 0){
					return response()->json(['status' => 'err', 'msg' => 'You have no name changes left.']);
				}
				$username = Input::get('username');
				if(preg_match("/[^a-zA-Z0-9_]+/", $username)){
					return response()->json(['status'=>'err','msg'=>'Username must be alphanumeric.']);
				}
				if(strlen($username) < 2){
					return response()->json(['status'=>'err','msg'=>'Username must be at least 2 characters long.']);
				}
				if(strlen($username) > 30){
					return response()->json(['status'=>'err','msg'=>'Username must be less than 30 characters.']);
				}
				if(!is_null(User::where('username', $username)->first())){
					return response()->json(['status'=>'err','msg'=>'Username is already in use']);
				}
				DB::transaction(function() use ($myUser, $username){
					DB::table('username_logs')->insert(['uid' => $myUser->id, 'username_before' => $myUser->username, 'username_after' => $username, 'changed_at' => Carbon\Carbon::now()]);
					$myUser->username = $username;
					$myUser->name_changes = $myUser->name_changes - 1;
					$myUser->save();
				});
				return response()->json(['status' => 'done']);
			}else if(Input::get('type') == "email"){
				if(empty(Input::get('value'))){
					$myUser->email = null;
					$myUser->save();
				}else{
					if(Input::get('value') == $myUser->email){
						return response()->json(['status'=>'done']);
					}
					if (!filter_var(Input::get('value'), FILTER_VALIDATE_EMAIL) || strlen(Input::get('value')) > 254) {
						return response()->json(['status'=>'err','msg'=>'Invalid email.']);
					}
					if(DB::table('users')->where('email', Input::get('value'))->count() > 0){
						return response()->json(['status'=>'err','msg'=>'Email is already in use.']);
					}
					$myUser->email = Input::get('value');
					$myUser->save();
				}
				return response()->json(['status'=>'done']);
			}else if(Input::get('type') == "password"){
				if(!empty(Input::get('oldpass') && !empty(Input::get('newpass')))){
					if(strlen(Input::get('newpass')) < 6){
						return $this->jsonError('Minimum length is 6 characters.');
					}
					if(strlen(Input::get('newpass')) > 50){
						return $this->jsonError('Maximum length is 50 characters.');
					}

					if(Input::get('oldpass') == Input::get('newpass')){
						return $this->jsonError('Password must be different to your current one.');
					}

					if(!password_verify(Input::get('oldpass'), $myUser->password)){
						return $this->jsonError('Current password is incorrect.');
					}
					$password = password_hash(Input::get('newpass'), PASSWORD_BCRYPT);
					$session = md5(str_shuffle('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'));
					
					$myUser->password = $password;
					$myUser->session = $session;
					$myUser->sess_end = floor(microtime(true) * 1000) + 604800000;
					$myUser->save();
					
					setcookie('session', $session, time() + 604800, '/', '.'.currentDomain());
					return $this->jsonError('Password successfully changed.');
				}else{
					return $this->jsonError('Fill all fields.');
				}
			}else if(Input::get('type') == "image"){
				if($myUser->role){
					$valid = array("jpg", "jpeg", "png", "gif", "webp");
				}else{
					$valid = array("jpg", "jpeg", "png", "webp");
				}

				$photokey = Input::get('modal');
				if ($photokey != "profile_pic" && $photokey != "banner_pic"){
					return $this->jsonError('Invalid Image type.');
				}
				
				$normalSize = 500; // 120 px

				if(!array_key_exists('image', $_FILES)){
					return $this->jsonError('Image not set.');
				}

				
				$file = $_FILES['image'];
				$ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
				$name = substr(str_shuffle(str_repeat("0123456789abcdef", 5)), 0, 32);
				$path = $cdnRoot . "/$photokey/"; // path to save to
				//return  $this->jsonError($path);

				
				$filelimit = 1024000; // 1mb; add sitesettings changeable
				if($myUser->role >= 1){
					$filelimit = 3072000; // 3mb
				}
				if($file['size'] > $filelimit){
					return  $this->jsonError('Image too large. Limit ' . $this->formatBytes($filelimit));
				}
			
				
				if(!isset($file['tmp_name']) || empty($file['tmp_name'])){
					return $this->jsonError($file);
				}
				
				$properties = getimagesize($file['tmp_name']); // resize image vvvv
				if($properties === false){
					return $this->jsonError('Error');
				}


				switch ($properties[2]){ // enum image type
					case IMAGETYPE_PNG:
						$simage = imagecreatefrompng($file['tmp_name']);
						$image = imagecreatefrompng($file['tmp_name']);

						$smallImage = $this->resizeImage($simage, $properties[0], $properties[1]);
						$normalImage = $this->resizeImage($image, $properties[0], $properties[1], $normalSize);

						imagepng($simage, $path . $name . '_50x50.'.$ext);
						imagepng($image, $path . $name.'.'.$ext);
						break;
					case IMAGETYPE_JPEG:
						$simage = imagecreatefromjpeg($file['tmp_name']);
						$image = imagecreatefromjpeg($file['tmp_name']);

						$smallImage = $this->resizeImage($simage, $properties[0], $properties[1]);
						$normalImage = $this->resizeImage($image, $properties[0], $properties[1], $normalSize);

						// logger on php8 would unironically destroy everything idk why
                        // logger('$simage: ' . $simage);
                        // logger('file: ' . $path . $name . '_50x50.'.$ext);
						imagejpeg($simage, $path . $name . '_50x50.'.$ext);
						imagejpeg($image, $path . $name.'.'.$ext);
						break;
					case IMAGETYPE_WEBP:
						$simage = imagecreatefromwebp($file['tmp_name']);
						$image = imagecreatefromwebp($file['tmp_name']);

						$smallImage = $this->resizeImage($simage, $properties[0], $properties[1]);
						$normalImage = $this->resizeImage($image, $properties[0], $properties[1], $normalSize);

						imagejpeg($simage, $path . $name . '_50x50.'.$ext);
						imagejpeg($image, $path . $name.'.'.$ext);
						break;
					case IMAGETYPE_GIF:
						if(!move_uploaded_file($file["tmp_name"], $path . $name.'.'.$ext)){
							return $this->jsonError('Error: Image not uploaded.');
						}
						break;
					default:
						return $this->jsonError('Invalid image type');
				}

				if(file_exists($path.$name.'.'.$ext)){
					if ($photokey == 'profile_pic'){
						$myUser->profile_pic = $name.'.'.$ext;
						if($properties[2] != IMAGETYPE_GIF){
							$myUser->has_small_profile_pic = 1;
						}
					}else if($photokey == 'banner_pic'){
						$myUser->banner_pic = $name.'.'.$ext;
					}
					$myUser->save();
				}else{
					return $this->jsonError('Error: Image not uploaded');
				}
				
				return response()->json(['status' => 'done', 'msg' => 'done']);

			}else if (Input::get('type') == "remove-image"){
				$bannerorpfp = Input::get('modal');

				$image_path = '';
				$smallimage_path = '';
				if ($bannerorpfp == "banner_pic") {
                    if ($myUser->banner_pic === null) {
                        return response()->json(['status' => 'done']);
                    }

					$image_path = "$cdnRoot/$bannerorpfp/".$myUser->banner_pic;
				    $smallimage_path = "$cdnRoot/$bannerorpfp/".explode('.', $myUser->banner_pic)[0].'_50x50.'.explode('.', $myUser->banner_pic)[1];
				} else if ($bannerorpfp == "profile_pic") {
                    if ($myUser->profile_pic === null) {
                        return response()->json(['status' => 'done']);
                    }

					$image_path = "$cdnRoot/$bannerorpfp/".$myUser->profile_pic;
					$smallimage_path = "$cdnRoot/$bannerorpfp/".explode('.', $myUser->profile_pic)[0].'_50x50.'.explode('.', $myUser->profile_pic)[1];
				} else {
                    return response()->json(['status' => 'err', 'msg' => 'Invalid image type']);
                }

				try {
					unlink($image_path);
					if ($myUser->has_small_profile_pic) {
						unlink($smallimage_path);
					}
				} catch (Exception $e) {
					 //return response()->json(['status' => 'err', 'msg' => 'Error... ' . $e]);
				} finally {
					if ($bannerorpfp == "banner_pic"){
					    $myUser->banner_pic = null;
					} else if($bannerorpfp == "profile_pic"){
						$myUser->profile_pic = null;
                        $myUser->has_small_profile_pic = 0;
					}

					$myUser->save();
					return response()->json(['status' => 'done']);
				}
			}else if(Input::get('type') == "change-bio"){
				if(!$myUser->isAdmin()){
					if(strlen(Input::get('value')) > 200){
						return response()->json(['status' => 'err', 'msg' => 'Bio too long; max length 200 characters.']);
					}
				}else{
					if(strlen(Input::get('value')) > 300){
						return response()->json(['status' => 'err', 'msg' => 'Bio too long; max length 300 characters.']);
					}
				}
				$myUser->bio = Input::get('value');
				$myUser->save();
				return response()->json(['status' => 'done']);
			}
			return response()->json(['status'=>'err', 'msg'=>'Error']);
		}
		if(!is_null($myUser)){
			return view('settings', ['myUser' => $myUser]);
		}
		return redirect('/login');
	}

	public function passwordreset($token, Request $request){
		$myUser = newGetUser();

		if($request->isMethod('post')){ // reset
			if($myUser != null){
				return response()->json(['status' => 'err', 'msg' => 'Logout before resetting password.']);
			}
			$reset = DB::table('password_reset')->where('link', $token)->first();
			$user = null;
			
			if(is_null($reset) || $reset->expires <= time()){
				if(!is_null($reset)){
					DB::table('password_reset')->where('id', $reset->id)->update(['expired' => 1]);
				}
				return response()->json(['status' => 'err', 'msg' => 'This token has expired or does not exist.']);
			}
			$user = User::where('id', $reset->user_id)->first();
			$pass = Input::get('pass');
			$confpass = Input::get('confpass');
			if($pass != $confpass){
				return response()->json(['status' => 'err', 'msg' => 'Passwords do not match.']);
			}
			if(strlen(Input::get('pass')) < 3){
				return response()->json(['status' => 'err', 'msg' => 'Minimum length is 3 characters.']);
			}
			if(strlen(Input::get('pass')) > 50){
				return response()->json(['status' => 'err', 'msg' => 'Maximum length is 50 characters.']);
			}
			$password = password_hash($pass, PASSWORD_BCRYPT);

			DB::transaction(function() use ($password, $reset, $user){
				$user->password = $password;
				$user->password_reset = Carbon\Carbon::now();
				$user->locked = 0;
				$user->save();
				
				DB::table('affected_usernames')->where('username', $user->username)->update(['unlocked' => true]);
				DB::table('password_reset')->where('id', $reset->id)->update(['used' => 1, 'expired' => 1]);
			});

			return response()->json(['status' => 'done', 'msg' => 'Password successfully changed.']);
			
		}

		$reset = DB::table('password_reset')->where('link', $token)->get();
		$user = null;
		if($reset->count() < 1){
			$reset = null;
		}else if($reset[0]->link != trim($token)){
			$reset = null;
		}else{
			$reset = $reset[0];
			
			if($reset->expires <= time()){
				DB::table('password_reset')->where('id', $reset->id)->update(['expired' => 1]);
			}
			$user = DB::table('users')->where('id', $reset->user_id)->get()[0];
		}
		return view('passwordreset', ['myUser' => $myUser, 'reset' => $reset, 'user' => $user]);
	}

	public function users(){
		$myUser = newGetUser();
		$members = User::latest('id')->limit(100)->get(['id', 'username', 'pastes', 'comments', 'joindate', 'role', 'name_color', 'name_css']);
		$rankedUsers = User::where('role', '!=', 0)->latest('id')->get(['id', 'username', 'pastes', 'comments', 'joindate', 'role', 'name_color', 'name_css']);
		$userCount = User::count();

		return view('users', [
			'myUser' => $myUser,
			'members' => $members,
			'rankedUsers' => $rankedUsers,
			'userCount' => $userCount,
		]);
	}

	public function search($query = '')
	{
		if (empty($query)) {
			return redirect('/users');
		}
		
		if (strlen($query) < 2) {
			return 'Minimum 2 chars';
		}
		
		$myUser = newGetUser();
	
		// using orderByRaw the right way with '?' for the query bindings
		$results = User::where('username', 'like', '%'.$query.'%')
			->orderByRaw('(username = ?) DESC', [$query])
			->orderByRaw('LENGTH(username)')
			->orderBy('id', 'desc')
			->get();
	
		// i didnt like how this looked before
		return view('users_search', [
			'query' => $query,
			'users' => $results,
			'myUser' => $myUser
		]);
	}

    public function followers($username){
        $myUser = newGetUser();
        if (is_null($myUser)) {
            // Users must log in to see this page.
            return RedirectResponse::create('/login');
        }
        $user = User::where('username', $username)->first();
        if(is_null($user)){
            return $this->jsonError();
        }

        $followers = DB::table('followers')
            ->where('uid', $user->id)
            ->orderBy('followed_at', 'desc')
            ->leftJoin('users', 'users.id', '=', 'followers.fid')
            ->get(['followers.*', ...MINIMUM_USER_COLUMNS_FOR_DISPLAY]);
        return view('user.followers', ['myUser' => $myUser, 'user' => $user, 'followers' => $followers]);
	}
	
    public function following($username){
        $myUser = newGetUser();
        if (is_null($myUser)) {
            // Users must log in to see this page.
            return RedirectResponse::create('/login');
        }
        $user = User::where('username', $username)->first();
        if(is_null($user)){
            return $this->jsonError();
        }
        $following = DB::table('followers')
            ->where('fid', $user->id)
            ->orderBy('followed_at', 'desc')
            ->leftJoin('users', 'users.id', '=', 'followers.uid')
            ->get(['followers.*', ...MINIMUM_USER_COLUMNS_FOR_DISPLAY]);
        return view('user.following', ['myUser' => $myUser, 'user' => $user, 'following' => $following]);
    }

    public function likes_received($username){
        $myUser = newGetUser();
        if(is_null($myUser)){
            return $this->jsonError();
        }
        $user = User::where('username', $username)->first();
        if(is_null($user)){
            return $this->jsonError();
        }
        $pastes = DB::table('pastes')->where('created_by', $user->id)->orderBy('created_at', 'desc')->get();
        return view('user.followers', ['myUser' => $myUser, 'user' => $user, 'pastes' => $pastes]);
	}

    public function comment(Request $request, $username){
		if(!$request->isMethod('post')){
			return $this->jsonError();
		}

        if (!$request->attributes->get('captcha', false)) {
			return $this->jsonError('Invalid captcha');
		}
		
        $myUser = newGetUser();
        if(is_null($myUser)){
            return $this->jsonError();
        }
        $user = User::where('username', $username)->first();
        if(is_null($user)){
            return $this->jsonError();
		}

		$content = Input::get('comment');

		// $comments = DB::table('profile_comments')->where('uid', $user->id)->orderBy('created_at', 'desc')->get();

		if(!is_null($content) && !empty($content) && (strlen($content) < 2 || strlen($content) > 100)){
			return $this->jsonError('Length must be between 2 and 100 chars');
		}

		if ($user->id === 11184) {
			return "Server Error";
		}

		if ($user->id === 451987) {
			return "Server Error";
		}
	
		if ($user->id === 399586) {
			return "Server Error";
		}
		
		DB::table('profile_comments')->insert(['uid' => $user->id, 'content' => $content, 'created_by' => $myUser->id, 'created_at' => Carbon\Carbon::now()]);
		
		return response()->json(['status' => 'done', 'username' => $myUser->getNameHtml(false, true)]);
	}

    public function removeComment(Request $request, $username){
		if(!$request->isMethod('post')){
			return $this->jsonError();
		}
		
        $myUser = newGetUser();
        if(is_null($myUser)){
            return $this->jsonError();
        }
        $user = User::where('username', $username)->first();
        if(is_null($user)){
            return $this->jsonError();
		}

		$cid = Input::get('commentID');

		if(DB::table('profile_comments')->where('id', $cid)->first() == null){
            return $this->jsonError();
		}

		DB::table('profile_comments')->where('id', $cid)->delete();
		
		return response()->json(['status' => 'done', 'username' => $user->getNameHtml(false, true)]);
	}
}

