<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Session;

use App\Models\Exam;
use App\Models\ExamResult;
use App\Models\Notice;
use App\Models\Schedule;
use App\Models\ScheduleStudentRel;
use App\Models\ScheduleSubjectRel;
use App\Models\Student;
use App\Models\Subject;
use App\Models\Teacher;
use App\Models\User;

use Yajra\DataTables\Facades\DataTables;

class StudentController extends Controller
{
  function returnToLogin()
  {
    return redirect()
      ->route('login')
      ->with('success', 'sorry but the session already timeout');
  }

  function errHandler($th)
  {
    $ERR_CANNOT_GET_EMAIL = 'Attempt to read property "email" on null';

    if ($ERR_CANNOT_GET_EMAIL == $th->getMessage()) {
      return $this->returnToLogin();
    } else {
      throw $th;
    }
  }

  public function helloworld()
  {
    return view('helloworld');
  }

  public function checkAnyNull($itemsToCheck)
  {
    $result = false;

    foreach ($itemsToCheck as $itemToCheck) {
      $result = $result || is_null($itemToCheck);
    }

    return $result;
  }

  /**
   * Display a listing of the resource.
   *
   * @return \Illuminate\Http\Response
   */
  public function index(Request $request)
  {
    try {
      Session::forget('status');

      return view('students.index', compact('request'));
    } catch (\Exception $e) {
      dd($e);
      return 'list student failed';
    }
  }

  /**
   * Show the form for creating a new resource.
   *
   * @return \Illuminate\Http\Response
   */
  public function create(Request $request)
  {
    try {
      return view('students.create', compact('request'));
    } catch (\Exception $e) {
      return 'add new student failed';
    }
  }

  /**
   * Store a newly created resource in storage.
   *
   * @param  \Illuminate\Http\Request  $request
   * @return \Illuminate\Http\Response
   */
  public function store(Request $request)
  {
    try {
      $validatedData = $request->validate([
        'firstName' => 'required',
        'lastName' => 'required',
        'dateOfBirth' => 'required',
        'gender' => '',
        'email' => 'required',
        'address' => 'required',
        'password' => 'required',
      ]);

      DB::beginTransaction();

      $user = new User();
      $user->name = join(', ', [
        $validatedData['firstName'],
        $validatedData['lastName'],
      ]);
      $user->email = $validatedData['email'];
      $user->password = $validatedData['password'];
      $user->role = 'student';
      $user->save();

      // NOTE: save user to get user_id, referenced by student
      $new_user_id = $user->id;

      $student = new Student();
      $student->firstName = $validatedData['firstName'];
      $student->lastName = $validatedData['lastName'];
      $student->dateOfBirth = $validatedData['dateOfBirth'];

      if (isset($validatedData['gender'])) {
        $student->gender = $validatedData['gender'];
      }

      $student->email = $validatedData['email'];
      $student->address = $validatedData['address'];
      $student->user_id = $new_user_id;

      if ($request->avatarAction == 'NO_CHANGE') {
        $student->avatar = null;
      } elseif ($request->avatarAction == 'CLEAR') {
        // NOTE: user intent clear avatar
        $student->avatar = null;
      } elseif ($request->avatarAction == 'UPDATE_AVATAR') {
        // NOTE: user intent change avatar
        $avatarFileName =
          str_replace('@', '_', str_replace('.', '_', $student->email)) .
          '.' .
          $request->avatar->getClientOriginalExtension();

        $request->avatar->move(public_path('avatars'), $avatarFileName);

        $student->avatar = $avatarFileName;
      }

      $student->save();

      DB::commit();

      Session::forget('status');

      return redirect()
        ->route('students.index')
        ->with('success', 'Student has been created successfully.');
    } catch (\Exception $e) {
      DB::rollback();
      $message = $e->getMessage();
      $request->session()->put('status', $message);
      return view('students.create', compact('request'));
      // return 'save student failed';
    }
  }

  /**
   * Display the specified resource.
   *
   * @param  \App\Student  $Student
   * @return \Illuminate\Http\Response
   */
  public function show(Student $student, Request $request)
  {
    try {
      $student_id = $student->id;
      $student = Student::with(['schedules'])
        ->where('id', '=', $student->id)
        ->get()[0];

      return view('students.show', compact('student', 'request'));
    } catch (\Exception $e) {
      dd($e);
      return 'show student failed';
    }
  }

  /**
   * Show the form for editing the specified resource.
   *
   * @param  \App\Student  $Student
   * @return \Illuminate\Http\Response
   */
  public function edit(Student $student, Request $request)
  {
    try {
      $student_id = $student->id;

      $schedules = Schedule::select()->get();
      $student_selected_subject_records = Schedule::with(['students'])
        ->whereRelation('students', 'students.id', '=', $student_id)
        ->get();

      $student_selected_subject_id = [];
      foreach ($student_selected_subject_records as $student_selected_subject_record) {
        array_push(
          $student_selected_subject_id,
          $student_selected_subject_record->id
        );
      }

      // dd($student_selected_subject_id);

      return view(
        'students.edit',
        compact(
          'request',
          'student',
          'schedules',
          'student_selected_subject_id'
        )
      );
    } catch (\Exception $e) {
      // dd($e);
      return 'edit student failed';
    }
  }

  /**
   * Update the specified resource in storage.
   *
   * @param  \Illuminate\Http\Request  $request
   * @param  \App\Student  $Student
   * @return \Illuminate\Http\Response
   */
  public function update(Request $request, Student $student)
  {
    try {
      $pattern = '/schedules_schedule_id_(\d+)/i';
      $request_all = $request->all();

      $validatedData = $request->validate([
        'firstName' => 'required',
        'lastName' => 'required',
        'dateOfBirth' => 'required',
        'gender' => '',
        'email' => 'required',
        'address' => 'required',
      ]);

      DB::beginTransaction();
      $student = Student::find($student->id);
      $user_id = $student->user_id;
      $user = User::find($user_id);

      $student->firstName = $validatedData['firstName'];
      $student->lastName = $validatedData['lastName'];
      $student->dateOfBirth = $validatedData['dateOfBirth'];
      if (isset($validatedData['gender'])) {
        $student->gender = $validatedData['gender'];
      }
      $student->email = $validatedData['email'];
      $student->address = $validatedData['address'];

      $user->name = join(', ', [
        $validatedData['firstName'],
        $validatedData['lastName'],
      ]);

      if ($request['password']) {
        $user->password = $request['password'];
      }

      if ($request->avatarAction == 'NO_CHANGE') {
      } elseif ($request->avatarAction == 'CLEAR') {
        // NOTE: user intent clear avatar
        $student->avatar = null;
      } elseif ($request->avatarAction == 'UPDATE_AVATAR') {
        // NOTE: user intent change avatar
        $avatarFileName =
          str_replace('@', '_', str_replace('.', '_', $student->email)) .
          '.' .
          $request->avatar->getClientOriginalExtension();

        $request->avatar->move(public_path('avatars'), $avatarFileName);

        $student->avatar = $avatarFileName;
      }

      // NOTE: update student applied subject
      $applied_subjects = $student->schedules;
      foreach ($applied_subjects as $key) {
        $student->schedules()->detach($key->id);
      }

      foreach ($request_all as $key => $value) {
        if (preg_match($pattern, $key, $m) == 1) {
          if ($value == 'on') {
            $schedule = Schedule::find($m[1]);
            if (is_null($schedule)) {
            } else {
              $student->schedules()->attach($schedule->id);
            }
          }
        }
      }

      $student->save();
      $user->save();

      DB::commit();

      Session::forget('status');

      return redirect()
        ->route('students.index')
        ->with('success', 'Student Has Been updated successfully');
    } catch (\Exception $e) {
      DB::rollback();

      dd($e);
      $message = $e->getMessage();
      $request->session()->put('status', $message);

      $schedules = Schedule::select()->get();

      return view('students.edit', compact('student', 'request', 'schedules'));
    }
  }

  /**
   * Remove the specified resource from storage.
   *
   * @param  \App\Student  $Student
   * @return \Illuminate\Http\Response
   */
  public function destroy(Student $student)
  {
    try {
      DB::beginTransaction();
      $student_id = $student->id;

      $student = Student::find($student_id);
      $user_id = $student->user_id;

      $user = User::find($user_id);

      $student->delete();
      if ($user) {
        $user->delete();
      }

      DB::commit();

      return redirect()
        ->route('students.index')
        ->with('success', 'Student has been deleted successfully');
    } catch (\Exception $e) {
      DB::rollback();
      // dd($e);
      return 'delete student failed';
    }
  }

  /**
   * Display a listing of the students in json format
   *
   * @return \Illuminate\Http\Response
   */
  public function getStudentsJson(Request $request)
  {
    try {
      $arr = [];
      if (is_null($request->query('q'))) {
        // NOTE: return all records
        $students = Student::all();
      } else {
        // NOTE: request with query word
        $q_word = $request->query('q');
        $students = Student::where('email', 'LIKE', '%' . $q_word . '%')->get();
      }

      foreach ($students as $row) {
        array_push($arr, [
          'id' => $row->id,
          'name' => $row->name,
          'studentId' => $row->studentId,
          'firstName' => $row->firstName,
          'lastName' => $row->lastName,
          'dateOfBirth' => $row->dateOfBirth,
          'gender' => $row->gender,
          'email' => $row->email,
          'address' => $row->address,
          'classRoom' => $row->classRoom,
          'parent' => $row->parent,
        ]);
      }

      return response()->json($arr);
    } catch (\Exception $e) {
      // dd($e);
      return 'getStudentsJson failed';
    }
  }

  public function getNumOfStudents()
  {
    try {
      $student_count = Student::count();

      return response()->json(['count' => "$student_count"]);
    } catch (\Exception $e) {
      // dd($e);
      return 'getNumOfStudents failed';
    }
  }

  public function setNoticeRead(Request $request, string $notice_id)
  {
    try {
      $notice = Notice::find($notice_id);

      $email_to_find = $request->user()->email;
      $current_student = Student::where('email', $email_to_find)->get()[0];

      $current_student->noticesRead()->attach($notice->id);

      return view(
        'students.showNotices',
        compact('request', 'current_student')
      );
    } catch (\Exception $e) {
      //throw $th;
      dd($e);
    }
  }

  public function showNotice(Request $request, string $notice_id)
  {
    try {
      $notice = Notice::find($notice_id);

      $email_to_find = $request->user()->email;
      $current_student = Student::where('email', $email_to_find)->get()[0];

      $current_student->noticesRead()->attach($notice->id);

      return view(
        'students.showNotice',
        compact('request', 'current_student', 'notice')
      );
    } catch (\Exception $e) {
      return redirect()->route('login');
    }
  }

  public function dtGetStudents()
  {
    try {
      //code...
      $students = Student::select([
        'id',
        'firstName',
        'lastName',
        'gender',
        'email',
      ]);

      return DataTables::eloquent($students)->toJson();
    } catch (\Exception $e) {
      dd($e);
      //throw $th;
    }
  }

  public function showInfo(Student $student, Request $request)
  {
    try {
      $email_to_find = $request->user()->email;
      $current_student = Student::where('email', $email_to_find)->get()[0];

      return view('students.showInfo', compact('request', 'current_student'));
    } catch (\Exception $e) {
      return $this->errHandler($e);
    }
  }

  public function updateInfo(Request $request)
  {
    try {
      $email_to_find = $request->user()->email;
      $current_student = Student::where('email', $email_to_find)->get()[0];
      $student_id = $current_student->id;

      $validatedData = $request->validate([
        'firstName' => 'required',
        'lastName' => 'required',
        'dateOfBirth' => 'required',
        'gender' => 'required',
        'email' => 'required',
        'address' => 'required',
      ]);

      DB::beginTransaction();

      $student = Student::find($student_id);
      $user_id = $student->user_id;
      $user = User::find($user_id);

      $student->firstName = $validatedData['firstName'];
      $student->lastName = $validatedData['lastName'];
      $student->dateOfBirth = $validatedData['dateOfBirth'];
      $student->gender = $validatedData['gender'];
      $student->email = $validatedData['email'];
      $student->address = $validatedData['address'];

      $user->name = join(', ', [
        $validatedData['firstName'],
        $validatedData['lastName'],
      ]);

      if ($request['password']) {
        $user->password = $request['password'];
      }

      if ($request->avatarAction == 'NO_CHANGE') {
        // $student->avatar = NULL;
      } elseif ($request->avatarAction == 'CLEAR') {
        // NOTE: user intent clear avatar
        $student->avatar = null;
      } elseif ($request->avatarAction == 'UPDATE_AVATAR') {
        // NOTE: user intent change avatar
        $avatarFileName =
          str_replace('@', '_', str_replace('.', '_', $student->email)) .
          '.' .
          $request->avatar->getClientOriginalExtension();

        $request->avatar->move(public_path('avatars'), $avatarFileName);

        $student->avatar = $avatarFileName;
      }

      // $student->fill($request->post())->save();
      $student->save();
      $user->save();

      DB::commit();
      Session::forget('status');

      return redirect()
        ->route('studentInfo')
        ->with('success', 'Student information has Been updated successfully');
    } catch (\Exception $e) {
      DB::rollback();
      dd($e);

      $message = $e->getMessage();
      $request->session()->put('status', $message);

      return view('students.showInfo', compact('student', 'request'));
    }
  }

  public function showDashboard(Request $request)
  {
    try {
      $email_to_find = $request->user()->email;
      $current_student = Student::where('email', $email_to_find)->get()[0];

      $num_of_subject_applied = Subject::count();
      $num_of_exam = Exam::with(['students'])
        ->whereRelation('students', 'students.id', '=', $current_student->id)
        ->count();
      $num_of_teacher = Teacher::count();
      $num_of_student = Student::count();
      $num_of_schedule = Schedule::with(['students'])
        ->whereRelation('students', 'students.id', '=', $current_student->id)
        ->count();

      Session::forget('status');

      return view(
        'students.showDashboard',
        compact(
          'request',
          'num_of_subject_applied',
          'num_of_exam',
          'num_of_schedule',
          'num_of_teacher',
          'num_of_student',
          'current_student'
        )
      );
    } catch (\Exception $e) {
      return redirect()->route('login');
    }
  }

  public function showNotifications(Request $request)
  {
    Session::forget('status');

    return view('students.work_in_progress');

    try {
      // return view('students.show.notifications.index', compact('request'));
    } catch (\Exception $e) {
      // dd($e);
      $message = $e->getMessage();
      $request->session()->put('status', $message);
      return view('student_dashboard', compact('student', 'request'));
    }
  }

  public function showSchedules(Request $request)
  {
    try {
      $email_to_find = $request->user()->email;
      $current_student = Student::with(['schedules'])
        ->where('email', $email_to_find)
        ->get()[0];
      $schedules = $current_student->schedules;

      Session::forget('status');

      return view(
        'students.showSchedules',
        compact('request', 'schedules', 'current_student')
      );
    } catch (\Exception $e) {
      // dd($e);

      DB::rollback();
      $message = $e->getMessage();
      $request->session()->put('status', $message);
      return view('student_dashboard', compact('student', 'request'));
    }
  }

  public function showSubjects(Request $request)
  {
    try {
      $email_to_find = $request->user()->email;

      $subjects = Subject::select(['id', 'subjectTitle'])
        ->where('deleted', '=', 'false')
        ->get();

      $schedules = Schedule::with(['subjects'])->get();

      $current_student = Student::with(['schedules'])
        ->where('email', $email_to_find)
        ->get()[0];

      $current_student_id = $current_student->id;

      // $student_selected_subject_records = Schedule::with(['students'  => function($q){
      //     $q->where('students.id', '=', 2);
      // }])->get();
      $student_selected_subject_records = Schedule::whereRelation(
        'students',
        'students.id',
        '=',
        $current_student_id
      )->get();

      $student_selected_subject_id = [];
      foreach ($student_selected_subject_records as $student_selected_subject_record) {
        array_push(
          $student_selected_subject_id,
          $student_selected_subject_record->id
        );
      }

      Session::forget('status');

      // students/show/subjects/index.blade.php
      return view(
        'students.showSubjects',
        compact(
          'request',
          'subjects',
          'current_student',
          'schedules',
          'student_selected_subject_id'
        )
      );
    } catch (\Exception $e) {
      DB::rollback();
      return $this->errHandler($e);

      // // dd($e);

      // $message = $th->getMessage();
      // $request->session()->put('status', $message);
      // return 'studentShowSubjects failed';
    }
  }

  public function updateSubject(Request $request)
  {
    // when student apply subject
    try {
      $pattern = '/schedules_schedule_id_(\d+)/i';

      $request_all = $request->all();

      $email_to_find = $request->user()->email;
      $student = Student::where('email', '=', $email_to_find)->get()[0];
      $student_id = $student->id;

      $student = Student::find($student_id);

      // NOTE: clear all applied subject
      // TODO: simplify to: $student->schedules()->detach();
      $applied_subjects = $student->schedules;
      foreach ($applied_subjects as $key) {
        $student->schedules()->detach($key->id);
      }

      foreach ($request_all as $key => $value) {
        if (preg_match($pattern, $key, $m) == 1) {
          if ($value == 'on') {
            $schedule = Schedule::find($m[1]);
            if (is_null($schedule)) {
            } else {
              $student->schedules()->attach($schedule->id);
            }
          }
        }
      }

      Session::forget('status');

      // return redirect()
      //     ->route('studentShowDashboard')
      //     ->with('success', 'update subject selection done');

      return redirect()
        ->route('studentShowSubjects')
        ->with('success', 'Subjects application success !');
    } catch (\Exception $e) {
      DB::rollback();

      $message = $e->getMessage();
      $request->session()->put('status', $message);

      return view('student_dashboard', compact('student', 'request'));
    }
  }

  public function clearAvatar(Request $request)
  {
    try {
      $request_all = $request->all();

      // $email_to_find = $request->user()->email;
      $email_to_find = 'student1@school.com';

      $student = Student::where('email', '=', $email_to_find)->get()[0];
      $student_id = $student->id;

      $student = Student::find($student_id);

      $avatar_file = $student->avatar;

      File::delete(public_path('avatars') . '/' . $avatar_file);

      $student->avatar = null;
      $student->save();

      return view('students.edit', compact('student', 'request'));
    } catch (\Exception $e) {
      throw $e;
    }
  }

  public function showNotices(Student $student, Request $request)
  {
    try {
      $email_to_find = $request->user()->email;
      $current_student = Student::where('email', $email_to_find)->get()[0];

      return view(
        'students.showNotices',
        compact('request', 'current_student')
      );
    } catch (\Exception $e) {
      return $this->errHandler($e);
    }
  }

  public function showExamResults(Request $request)
  {
    try {
      $email_to_find = $request->user()->email;
      $current_student = Student::where('email', $email_to_find)->get()[0];

      $student_id = $current_student->id;

      $exam_results = ExamResult::where('student_id', '=', $student_id)->get();

      $teachers_from_db = Teacher::all();
      $teachers = [];
      foreach ($teachers_from_db as $teacher) {
        $teachers[$teacher->id] = $teacher;
      }

      $exams = [];
      $exams_from_db = Exam::all();
      foreach ($exams_from_db as $exam) {
        $exams[$exam->id] = $exam;
      }

      return view(
        'students.showExamResults',
        compact(
          'request',
          'current_student',
          'exam_results',
          'exams',
          'teachers'
        )
      );
    } catch (\Exception $e) {
      throw $e;
      return route('studentShowDashboard');
    }
  }

  public function showExamResult(Request $request, string $exam_result_id)
  {
    try {
      $exam_result = ExamResult::find($exam_result_id);

      $email_to_find = $request->user()->email;
      $current_student = Student::where('email', $email_to_find)->get()[0];

      return view(
        'students.showExamResult',
        compact('request', 'current_student', 'exam_result')
      );
    } catch (\Exception $e) {
      //throw $th;
      dd($e);
    }
  }

  public function dtGetStudentSimpleSchedules(
    Request $request,
    string $student_id
  ) {
    $schedules = Schedule::with(['classrooms', 'subjects', 'students'])
      ->whereRelation('students', 'students.id', '=', $student_id)
      ->orderBy('id', 'desc')
      ->limit(10)
      ->get();

    return response()->json($schedules);
  }

  public function dtGetStudentSimpleExams(Request $request, string $student_id)
  {
    $exams = Exam::with(['subject', 'students'])
      ->whereRelation('students', 'students.id', '=', $student_id)
      ->orderBy('id', 'desc')
      ->limit(10)
      ->get();

    return response()->json($exams);
  }
}
