<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Contracts\Routing\ResponseFactory;
use App\User;
use Validator;
use DB, Hash, Mail, Illuminate\Support\Facades\Password;

use App\Http\Controllers\PermissionController;
use Illuminate\Support\Facades\Log;

class AuthController extends Controller {
  private $objPermission;

  public function __construct() {
    $this->objPermission = new PermissionController();
  }

  public function checkSelf(Request $r) { // /api/auth/checkself
    $check = $this->checkLegit($r->kero_token);
    return array($check);
  }

  public function checkLegit ($t) {
    if (!isset($t) || empty($t) || is_null($t)) return 0;
    $check = DB::table('users')->select('id')->where('kero_token', $t)->first();
    return $check->id;
  }

  public function getPerms(Request $r) { // /api/auth/getpermissions
    $check = $this->getPermissions($r->kero_token);

    return array($check);
  }

  public function getPermissions($token) {
    $check = $this->checkLegit($token);

    $perm = DB::table('usr_perm_id')
      ->select('perm_id')
      ->where('user_id', $check)
      ->first();

    $perm = json_decode(json_encode($perm), true);

    // Does the user ID exist? Grand the appropriate rights. Otherwise, use guest.
    if ($check != 0) {
      // Page permissions.
      $grouppermblg = $this->objPermission->getPermissionGroup('blg', $perm['perm_id']);
      $userpermblg = $this->objPermission->getPermissionUser('blg', $check);

      // Board permissions.
      $grouppermfor = $this->objPermission->getPermissionGroup('for', $perm['perm_id']);
      $userpermfor = $this->objPermission->getPermissionUser('for', $check);

      // Store permissions.
      $grouppermstr = $this->objPermission->getPermissionGroup('str', $perm['perm_id']);
      $userpermstr = $this->objPermission->getPermissionUser('str', $check);

      // User permissions.
      $grouppermusr = $this->objPermission->getPermissionGroup('usr', $perm['perm_id']);
      $userpermusr = $this->objPermission->getPermissionUser('usr', $check);

      // Image permissions.
      $grouppermimg = $this->objPermission->getPermissionGroup('img', $perm['perm_id']);
      $userpermimg = $this->objPermission->getPermissionUser('img', $check);

      // Invoice permissions.
      $groupperminv = $this->objPermission->getPermissionGroup('inv', $perm['perm_id']);
      $userperminv = $this->objPermission->getPermissionUser('inv', $check);

      // Now provide an array of user overwritten permissions if it exists. Otherwise, give its group permissions.
      $blgarr = array();
      $forarr = array();
      $strarr = array();
      $usrarr = array();
      $imgarr = array();
      $invarr = array();

      if (!empty($userpermblg[0])) {
        $blgarr = (array)$userpermblg[0];
      }
      else {
        $blgarr = (array)$grouppermblg[0];
      }

      $blgarr = array_combine(
        array_map(function($k){ return 'blg_'.$k; }, array_keys($blgarr)),
        $blgarr
      );

      if (!empty($userpermfor[0])) {
        $forarr = (array)$userpermfor[0];
      }
      else {
        $forarr = (array)$grouppermfor[0];
      }

      $forarr = array_combine(
        array_map(function($k){ return 'for_'.$k; }, array_keys($forarr)),
        $forarr
      );

      if (!empty($userpermstr[0])) {
        $strarr = (array)$userpermstr[0];
      }
      else {
        $strarr = (array)$grouppermstr[0];
      }

      $strarr = array_combine(
        array_map(function($k){ return 'str_'.$k; }, array_keys($strarr)),
        $strarr
      );

      if (!empty($userpermusr[0])) {
        $usrarr = (array)$userpermusr[0];
      }
      else {
        $usrarr = (array)$grouppermusr[0];
      }

      $usrarr = array_combine(
        array_map(function($k){ return 'usr_'.$k; }, array_keys($usrarr)),
        $usrarr
      );

      if (!empty($userperminv[0])) {
        $invarr = (array)$userperminv[0];
      }
      else {
        $invarr = (array)$groupperminv[0];
      }

      $invarr = array_combine(
        array_map(function($k){ return 'inv_'.$k; }, array_keys($invarr)),
        $invarr
      );

      if (!empty($userpermimg[0])) {
        $imgarr = (array)$userpermimg[0];
      }
      else {
        $imgarr = (array)$grouppermimg[0];
      }

      $merge = array();
      $merge1 = array();
      $merge2 = array();
      $merge3 = array();
      $merge4 = array();

      $merge1 = array_merge($blgarr, $forarr);
      $merge2 = array_merge($strarr, $usrarr);
      $merge3 = array_merge($merge1, $merge2);
      $merge4 = array_merge($merge3, $invarr);

      $merge = array_merge($merge4, $imgarr);

      return $merge;
    }
    else {
      // Page permissions.
      $grouppermblg = $this->objPermission->getPermissionGroup('blg', 6);

      // Forum permissions.
      $grouppermfor = $this->objPermission->getPermissionGroup('for', 6);

      // Store permissions.
      $grouppermstr = $this->objPermission->getPermissionGroup('str', 6);

      // User permissions.
      $grouppermusr = $this->objPermission->getPermissionGroup('usr', 6);

      // Image permissions.
      $grouppermimg = $this->objPermission->getPermissionGroup('img', 6);

      // Invoice permissions.
      $groupperminv = $this->objPermission->getPermissionGroup('inv', 6);

      // Since guests don't have user overwritten permissions, simply return the group permissions.
      (array)$grouppermblg[0] = array_combine(
        array_map(function($k){ return 'blg_'.$k; }, array_keys((array)$grouppermblg[0])),
        (array)$grouppermblg[0]
      );

      (array)$grouppermfor[0] = array_combine(
        array_map(function($k){ return 'for_'.$k; }, array_keys((array)$grouppermfor[0])),
        (array)$grouppermfor[0]
      );

      (array)$grouppermstr[0] = array_combine(
        array_map(function($k){ return 'str_'.$k; }, array_keys((array)$grouppermstr[0])),
        (array)$grouppermstr[0]
      );

      (array)$grouppermusr[0] = array_combine(
        array_map(function($k){ return 'usr_'.$k; }, array_keys((array)$grouppermusr[0])),
        (array)$grouppermusr[0]
      );

      (array)$grouppermimg[0] = array_combine(
        array_map(function($k){ return 'img_'.$k; }, array_keys((array)$grouppermimg[0])),
        (array)$grouppermimg[0]
      );

      (array)$groupperminv[0] = array_combine(
        array_map(function($k){ return 'inv_'.$k; }, array_keys((array)$groupperminv[0])),
        (array)$groupperminv[0]
      );

      $merge = array();
      $merge1 = array();
      $merge2 = array();
      $merge3 = array();
      $merge4 = array();

      $merge1 = array_merge((array)$grouppermblg[0], (array)$grouppermfor[0]);
      $merge2 = array_merge((array)$grouppermstr[0], (array)$grouppermusr[0]);
      $merge3 = array_merge($merge1, $merge2);
      $merge4 = array_merge($merge3, (array)$groupperminv[0]);

      $merge = array_merge($merge4, (array)$grouppermimg[0]);

      return $merge;
    }
  }

  public function register (Request $r) {
    $ip = $_SERVER['REMOTE_ADDR'];

    if (!empty($r)) {
      $existUser = DB::table('users')->select('id')->where('username', $r->username)->count();
      if ($existUser != 0) return array('err' => 'ユーザ名は既に登録しています。');
      if (empty($r->username)) return array('err' => 'ユーザ名は空です。');
      if (preg_match("/^[a-zA-Z0-9]+$/", $r->username) == 0) return array('err' => '英文字ばかりご入力下さい。');
      if (empty($r->password)) return array('err' => 'パスワードは空です。');
      if (empty($r->password_check)) return array('err' => 'パスワード（確認）は空です。');
      if ($r->password < 8) return array('err' => 'パスワードは8文以上をご入力下さい。');
      if ($r->password != $r->password_check) return array('err' => 'パスワードとパスワード（確認）は違います。');
      $existEmail = DB::table('users')->select('id')->where('email', $r->email)->count();
      if ($existEmail != 0) return array('err' => 'メールアドレスは既に登録しています。');
      if (empty($r->email)) return array('err' => 'メールアドレスは空です。');
      if (!filter_var($r->email, FILTER_VALIDATE_EMAIL)) return array('err' => 'メールアドレスを正しくご入力下さい。');

      $salt = dechex(mt_rand(0, 2147483647)) . dechex(mt_rand(0, 2147483647));
      $passwd = hash('sha256', $r->password . $salt);

      for ($round = 0; $round < 65536; $round++) { $passwd = hash('sha256', $passwd . $salt); }

      $addUser = DB::table('users')
        ->insertGetId([
          'username' => $r->username,
          'email' => $r->email,
          'password' => $passwd,
          'salt' => $salt,
          'remember_token' => '',
          'kero_token' => $this->makeToken()
        ]);

      DB::table('usr_details')
        ->insert([
          'user_id' => $addUser,
          'total_posts' => 0,
          'total_threads' => 0,
          'reg_date' => time(),
          'last_post_date' => 0,
          'last_post_location' => 0,
          'ontime' => 0,
          'strikes' => 0
        ]);

      DB::table('usr_contacts')
        ->insert([
          'user_id' => $addUser,
          'website_link' => '',
          'website_name' => '',
          'youtube_link' => '',
          'youtube_name' => '',
          'bitchute' => '',
          'niconico' => '',
          'pixiv' => '',
          'discord' => '',
          'mastodon' => '',
          'twitter' => '',
          'facebook' => '',
          'instagram' => ''
        ]);

      DB::table('usr_profile')
        ->insert([
          'user_id' => $addUser,
          'gender' => ($r->gender ? $r->gender : 0),
          'member_title' => '',
          'website_address' => '',
          'website_name' => '',
          'location' => '',
          'birthday' => 0,
          'bio' => '',
          'ip_address' => $ip,
          'avatar' => '',
          'ostatus' => 1,
          'header' => '',
          'footer' => '',
          'post_style' => '',
          'signature' => '',
          'name_style' => '',
          'display_name' => '',
          'yt_channel' => '',
          'country' => ($r->country ? $r->country : 'Japan'),
          'date_format' => '',
          'isClock24' => 1,
          'isShowSeconds' => 1,
          'isShowTimezone' => 1
        ]);

      DB::table('usr_perm_id')
        ->insert([
          'user_id' => $addUser,
          'perm_id' => 4,
          'usr_per_id' => 4,
          'img_per_id' => 4,
          'blg_per_id' => 4,
          'for_per_id' => 4,
          'sbx_per_id' => 4,
          'str_per_id' => 4,
          'doc_per_id' => 4,
          'odb_per_id' => 4,
          'inv_per_id' => 4,
        ]);

      $checkName = DB::table('users')->select('kero_token')->where('id', $addUser)->first();

      setcookie('kero_token', $checkName->kero_token, time()+157788000, '/', $_SERVER['HTTP_HOST'], 0, 1);
      return $this->login($r);

      //return array('1');
    }

    return array();
  }

  public function login (Request $r) {
    if (!empty($r)) {
      $checkName = DB::table('users')->where('username', $r->username)->first();

      if ($checkName) {
        // $checkName = json_decode(json_encode($checkName), true);
        $checkPass = hash('sha256', $r->password . $checkName->salt);

        for ($round = 0; $round < 65536; $round++) {
          $checkPass = hash('sha256', $checkPass . $checkName->salt);
        }

        if (hash_equals($checkPass, $checkName->password)) {
          if (!$checkName->kero_token) {
            $checkName->kero_token = $this->makeToken();
            DB::table('users')->where('id', $checkName->id)->update(['kero_token' => $checkName->kero_token]);
          }

          setcookie('kero_token', $checkName->kero_token, time()+157788000, '/', $_SERVER['HTTP_HOST'], 0, 1);
          return array('uid' => $checkName->id, 'kero_token' => $checkName->kero_token);
        }
      }
      return array('err' => 'ユーザ名又はパスワードを間違いました。');
    }

    return array('err' => 'フォームは空です。');
  }

  function makeToken() {
    $c  = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$!%&()';
    $clen = strlen($c);
    $token = '';

    for ($i = 0; $i < 128; $i++) {
      $token .= $c[rand(0, $clen - 1)];
    }

    return $token;
  }

  function CheckEmail($email) {
    $get = DB::table('users')
      ->where('email', $email)
      ->count();

    if ($get == 0) return 0;
    else return 1;
  }

  public function SendReset(Request $r) {
    $exist = $this->CheckEmail($r->email);

    if ($exist == 0) {
      return 0;
    }
    else {
      $check = DB::table('usr_resets')
        ->select('token')
        ->where('email', $r->email)
        ->count();

      if ($check > 0) {
        DB::table('usr_resets')
          ->where('email', $r->email)
          ->delete();
      }

      $token = bin2hex(random_bytes(32));
      $due = time() + (1 * 24 * 60 * 60);

      DB::table('usr_resets')
        ->insert([
          'email' => $r->email,
          'token' => $token,
          'due_date' => $due
        ]);

      $get = DB::table('usr_resetmails')
        ->select('sender', 'sendname', 'subject', 'message')
        ->first();

      $user = DB::table('users')
        ->select('username')
        ->where('email', $r->email)
        ->first();

      $mess = str_replace('{user}', $user->username, $get->message);
      $mess2 = str_replace('{link}', $token, $mess);

      $mess2 = mb_convert_encoding($mess2, "ISO-2022-JP", "AUTO");
      $subj = mb_convert_encoding($get->subject, "ISO-2022-JP", "AUTO");

      $headers  = "MIME-Version: 1.0"."\r\n";
      $headers .= "Content-Type: text/plain; charset=ISO-2022-JP"."\r\n";
      $headers .= "To: ".$r->email."\r\n";
      $headers .= "From: ".mb_convert_encoding($get->sendname,"ISO-2022-JP","AUTO")." <".$get->sender.">"."\r\n";

      mb_language("ja");

      $res = mail(
        $r->email,
        $subj,
        $mess2,
        $headers,
        "-f".$get->sender
      );

      return 1;
    }
  }

  public function ConfirmReset($token) {
    $get = DB::table('usr_resets')
      ->select('*')
      ->where('token', $token)
      ->first();

    $within24hour = time() + (1 * 24 * 60 * 60);

    if (empty($get)) {
      return 0;
    }
    else {
      if ($get->due_date > $within24hour) {
        return 0;
      }
      else {
        return 1;
      }
    }
  }

  public function PasswordReset(Request $r) {
    if (empty($r->password)) {
      return 0;
    }

    $salt = dechex(mt_rand(0, 2147483647)) . dechex(mt_rand(0, 2147483647));
    $passwd = hash('sha256', $r->password . $salt);

    for ($round = 0; $round < 65536; $round++) {
      $passwd = hash('sha256', $passwd . $salt);
    }

    $res = DB::table('users')
      ->where('email', $r->email)
      ->update([
        'password' => $passwd,
        'salt' => $salt
      ]);

    return 1;
  }

  public function recover(Request $r) {
    $user = User::where('email', $r->email)->first();

    if (!$user) {
      $error_message = "Your email address was not found.";
      return response()->json(['success' => false, 'error' => ['email'=> $error_message]], 401);
    }
    try {
      Password::sendResetLink($r->only('email'), function (Message $message) {
        $message->subject('Your Password Reset Link');
      });
    } catch (\Exception $e) {
      $error_message = $e->getMessage();
      return response()->json(['success' => false, 'error' => $error_message], 401);
    }

    return response()->json([
      'success' => true, 'data'=> ['message'=> 'A reset email has been sent! Please check your email.']
    ]);
  }

  public function checkAuth(Request $r) {
    $get = DB::table('users')
      ->select('id', 'kero_token')
      ->where('kero_token', $r->kero_token)
      ->first();

    $get = json_decode(json_encode($get), true);

    return $get;
  }

  public function logout () {
    if (isset($_COOKIE['kero_token'])) {
      unset($_COOKIE['kero_token']);
      setcookie('kero_token', '', time() - 3600, '/', $_SERVER['HTTP_HOST'], 0, 1);
    }

    return redirect('');
  }
}
