<?php

namespace App\Repositories;

use App\Models\AssetHistory;
use App\User;
use App\Models\EmployeeType;
use Carbon\Carbon;
use App\Repositories\TermAssets;
use Illuminate\Support\Facades\DB;

class UserRepository
{
    private $termAssetsRepo;
    public function __construct(TermAssets $termAssetsRepo)
    {
        $this->termAssetsRepo = $termAssetsRepo;
    }

    public function getUsers()
    {
        return User::superAdmin()
            ->with(['employeeType', 'department', 'position', 'location', 'assets', 'manager', 'userType'])
            ->withCount('assets');
    }

    public function getNextWeekNewHireUsers()
    {
        $bpoEmployeeType = EmployeeType::where('slug', 'bpo')->first();
        return User::superAdmin()
            ->with(['employeeType', 'department', 'position', 'location', 'assets'])
            ->withCount('assets')
            ->whereDate('hire_date', '>=', get_next_week_first_day())
            ->whereDate('hire_date', '<=', get_next_second_week_last_day())
            ->where('employee_type_id', '<>', $bpoEmployeeType->id);
    }

    public function searchUserWithGeneralQueries($users, $searchText)
    {
        if ($searchText) {
            $users = $users->where(function ($query) use ($searchText) {
                $query->where(function ($query) use ($searchText) {
                    $query->where('first_name', 'like', $searchText . '%')
                        ->orWhere('last_name', 'like', $searchText . '%')
                        ->orWhere('employee_id', $searchText)
                        ->orWhereRaw("CONCAT(`first_name`, ' ', `last_name`) like ?", [$searchText . '%'])
                        ->orWhere('email', 'like', $searchText . '%');
                })
                    ->orWhereHas('position', function ($query) use ($searchText) {
                        $query->where('name', 'like', '%' . $searchText . '%');
                    })
                    ->orWhereHas('employeeType', function ($query) use ($searchText) {
                        $query->where('name', 'like', '%' . $searchText . '%');
                    })
                    ->orWhereHas('department', function ($query) use ($searchText) {
                        $query->where('name', 'like', '%' . $searchText . '%');
                    })
                    ->orWhere('city', 'like', '%' . $searchText . '%');
            });
        }

        return $users;
    }

    public function searchUserWithSystemRole($users, $systemRole)
    {
        if ($systemRole) {
            if (is_array($systemRole)) {
                $users = $users->whereIn('user_type_id', $systemRole);
            } else {
                $users = $users->where('user_type_id', $systemRole);
            }
        }

        return $users;
    }

    public function searchUserWithNumberOfAssets($users, $noOfAssets)
    {
        if ($noOfAssets != '') {
            $users = $users->has('assets', '=', $noOfAssets);
        }

        return $users;
    }

    public function searchUserWithToDate($users, $dateTo)
    {
        if ($dateTo && isDateString($dateTo)) {
            $dateTo = convert_to_db_date($dateTo);
            if ($dateTo != null)
                $users = $users->where('hire_date', '<=', $dateTo);
        }

        return $users;
    }

    /**
     * Search newhire with from date , if no from date given uses current date
     * @param mixed $users
     * @param mixed $dateFrom
     * 
     * @return [type]
     */
    public function searchUserWithFromDate($users, $fromDate)
    {
        if ($fromDate != null) {
            $users = $users->where('hire_date', '>=', convert_to_db_date($fromDate));
        }

        return $users;
    }

    /**
     * Search newhire with from date , if no from date given uses current date
     * @param mixed $users
     * @param mixed $dateFrom
     * 
     * @return [type]
     */
    public function searchNewhireUserWithFromDate($users, $dateFrom)
    {
        //$fromDate = Carbon::now()->toDateTimeString();
        if ($dateFrom && isDateString($dateFrom)) {
            $fromDate = convert_to_db_date($dateFrom);
            if ($fromDate != null) {
                $users = $users->where('hire_date', '>=', $fromDate);
            }
        }

        /*if ($fromDate != null) {
            $users = $users->where('hire_date', '>=', $fromDate);
        }*/

        return $users;
    }

    public function searchUserThatHaveAssets($users, $haveAssets)
    {
        if ($haveAssets != 'select') {
            if ($haveAssets == 1) {
                $users = $users->has('assets');
            } elseif ($haveAssets == 2) {
                $users = $users->doesntHave('assets');
            }
        }

        return $users;
    }

    public function searchUserWithStatus($users, $status)
    {
        if ($status != 'select') {
            if ($status == 1) {
                $users = $users->active();
            } elseif ($status == 2) {
                $users = $users->inActive();
            }
        }

        return $users;
    }

    public function searchUserWithLegalHold($users, $legalHold)
    {
        if ($legalHold != 'select') {
            if ($legalHold == 1) {
                $users = $users->legalHold();
            } elseif ($legalHold == 2) {
                $users = $users->notLegalHold();
            }
        }

        return $users;
    }

    public function searchUserWithWorkLocation($users, $workLocation)
    {
        if ($workLocation) {
            if (is_array($workLocation)) {
                $users  = $users->where(function ($query) use ($workLocation) {
                    foreach ($workLocation as $key => $location) {
                        if ($key == 0) {
                            $query->where('city', 'like', '%' . $location . '%');
                        } else {
                            $query->orWhere('city', 'like', '%' . $location . '%');
                        }
                    }
                });
            } else {
                $users = $users->where('city', 'like', '%' . $workLocation . '%');
            }
        }

        return $users;
    }

    public function searchUserWithEmployeeType($users, $employeeType)
    {
        if ($employeeType) {
            if (is_array($employeeType)) {
                $users = $users->whereIn('employee_type_id', $employeeType);
            } else {
                $users = $users->where('employee_type_id', $employeeType);
            }
        }

        return $users;
    }

    public function searchUserWithEmployeeID($users, $employeeID)
    {
        if ($employeeID) {
            if (is_array($employeeID)) {
                $users = $users->whereIn('employee_id', $employeeID);
            } else {
                $users = $users->where('employee_id', $employeeID);
            }
        }

        return $users;
    }

    public function searchUserWithCountry($users, $country)
    {
        if ($country) {
            if (is_array($country)) {
                $users = $users->whereIn('country_id', $country);
            } else {
                $users = $users->where('country_id', $country);
            }
        }

        return $users;
    }

    public function searchUserWithMobilePhoneAssigned($users, $hasMobilePhoneAssigned)
    {
        if ($hasMobilePhoneAssigned != 'select') {
            if ($hasMobilePhoneAssigned == 1) {
                $users = $users->hasMobilePhoneAssigned();
            } elseif ($hasMobilePhoneAssigned == 2) {
                $users = $users->hasNoMobilePhone();
            }
        }

        return $users;
    }

    public function searchUserWithAssetTypeAndStatus($users, $assetType, $assetStatus)
    {
        if ($assetType && $assetStatus) {
            $users = $users->whereHas('assets', function ($query) use ($assetType, $assetStatus) {
                if (is_array($assetType) && is_array($assetStatus)) {
                    $query->whereIn('asset_type_id', $assetType)->whereIn('asset_status_id', $assetStatus);
                }
                if (is_array($assetType) && !is_array($assetStatus)) {
                    $query->whereIn('asset_type_id', $assetType)->where('asset_status_id', $assetStatus);
                }
                if (!is_array($assetType) && is_array($assetStatus)) {
                    $query->where('asset_type_id', $assetType)->whereIn('asset_status_id', $assetStatus);
                }
                if (!is_array($assetType) && !is_array($assetStatus)) {
                    $query->where('asset_type_id', $assetType)->where('asset_status_id', $assetStatus);
                }
            });
            return $users;
        }

        if ($assetType) {
            $users = $users->whereHas('assets', function ($query) use ($assetType) {
                if (is_array($assetType)) {
                    $query->whereIn('asset_type_id', $assetType);
                } else {
                    $query->where('asset_type_id', $assetType);
                }
            });
            return $users;
        }

        if ($assetStatus) {
            $users = $users->whereHas('assets', function ($query) use ($assetStatus) {
                if (is_array($assetStatus)) {
                    $query->whereIn('asset_status_id', $assetStatus);
                } else {
                    $query->where('asset_status_id', $assetStatus);
                }
            });
            return $users;
        }

        return $users;
    }

    public function searchUserWithAssetStatus($users, $assetStatus)
    {
        if ($assetStatus) {
            $users = $users->whereHas('assets', function ($query) use ($assetStatus) {
                if (is_array($assetStatus)) {
                    $query->whereIn('asset_status_id', $assetStatus);
                } else {
                    $query->where('asset_status_id', $assetStatus);
                }
            });
        }
        return $users;
    }


    public function searchUserWithManager($users, $manager)
    {
        if ($manager) {
            if (is_array($manager)) {
                $users = $users->whereIn('manager_id', $manager);
            } else {
                $users = $users->where('manager_id', $manager);
            }
        }

        return $users;
    }

    public function searchUserWithDepartment($users, $department)
    {
        if ($department) {
            if (is_array($department)) {
                $users = $users->whereIn('department_id', $department);
            } else {
                $users = $users->where('department_id', $department);
            }
        }

        return $users;
    }

    public function searchUserWithTerminationDate($users, $dateFrom, $dateTo)
    {
        if ($dateTo && isDateString($dateTo)) {
            $dateTo = convert_to_db_date($dateTo);
            if ($dateTo != null) {
                $users = $users->where('terminated_date', '<=', $dateTo);
            }
        }

        if ($dateFrom && isDateString($dateFrom)) {
            $dateFrom = convert_to_db_date($dateFrom);
            if ($dateFrom != null) {
                $users = $users->where('terminated_date', '>=', $dateFrom);
            }
        }

        return $users;
    }

    /**
     * Making query for `Active Users with No Assets Assigned` report
     *
     * @return App\User
     */
    public function getActiveUsersWithNoAssets()
    {
        return User::superAdmin()
            ->active()
            ->with(['department', 'location', 'manager'])
            ->doesntHave('assets');
    }

    /**
     * @return [type]
     */
    public function getUsersWithAssetHistory()
    {
        return User::superAdmin()
            ->select('users.id', 'users.status', 'users.employee_type_id', 'employee_id', 'asset_histories.created_at as assigned_date')
            ->leftJoin('asset_histories', function ($join) {
                $join->on('asset_histories.new_user_id', '=', 'users.id')
                    ->where('asset_histories.new_value', 'Assigned');
            })
            ->join('employee_types', 'employee_types.id', '=', 'users.employee_type_id')
            ->where('employee_types.slug', 'employee')
            ->active()
            ->with(['employeeType', 'department', 'position', 'location', 'assets']);
    }

    /**Gets the list of new hire users
     * 
     *
     * @return [type]
     */
    public function getNewHires()
    {

        // $users =  User::with([
        //     'userJiraMappings',
        //     'employeeType', 'position',
        //     'department', 'department.hardwarekits',
        //     'assets:id,user_id,location_id,make_and_model_id,technical_spec_id,serial_no,asset_tag,asset_type_id,asset_status_id',
        //     'assets.makeAndModel:id,name',
        //     'department.hardwarekits.makeAndModel:id,name',
        //     'department.hardwarekits.technicalSpec:id,details'
        // ])->superAdmin();

        $users = User::with([
            'userJiraMappings',
            'employeeType', 'position',
            'department', 'department.hardwarekits',
            'assets:id,user_id,location_id,make_and_model_id,technical_spec_id,serial_no,asset_tag,asset_type_id,asset_status_id',
            'assets.makeAndModel:id,name',
            'department.hardwarekits.makeAndModel:id,name',
            'department.hardwarekits.technicalSpec:id,details',
            'newUserAssetHistory' => function ($query) {
                $query->select('id', 'asset_id', 'user_id', 'new_user_id', 'new_value', 'action', 'created_at')->with('user:id,first_name,last_name')
                    ->whereHas('asset', function ($query) {
                        $query->hasAssetType('laptop')->hasAnyAssetStatus(['assigned', 'loaned']);
                    })->where('action', 'status_updated')
                    ->whereIn('new_value', ['Assigned', 'Loaned'])
                    ->latest();
            }
        ])->superAdmin();

        return $users;
    }

    /**
     * Gets new hire users between two dates
     * @param mixed $fromDate
     * @param null $toDate
     * 
     * @return [type]
     */
    public function getHireUsersBetweenDate($fromDate, $toDate = null)
    {
        $query = User::superAdmin()
            ->whereDate('hire_date', '>=', $fromDate);

        if ($toDate) {
            $query->whereDate('hire_date', '<=', $toDate);
        }

        return $query;
    }


    /**For filtering
     * @param mixed $newHires
     * @param mixed $searchText
     * 
     * @return [type]
     */
    public function searchWithGeneralQueries($newHires, $searchText)
    {
        if ($searchText) {
            $newHires = $newHires->where(function ($query) use ($searchText) {
                $query->where(function ($query) use ($searchText) {
                    $query->where('first_name', 'like', $searchText . '%')
                        ->orWhere('last_name', 'like', $searchText . '%')
                        ->orWhere('employee_id', $searchText)
                        ->orWhereRaw("CONCAT(`first_name`, ' ', `last_name`) like ?", [$searchText . '%'])
                        ->orWhere('email', 'like', $searchText . '%');
                });
            });
        }

        return $newHires;
    }

    public function searchWithNumberOfAssets($newHires, $noOfAssets)
    {
        if ($noOfAssets != '') {
            $newHires = $newHires->has('assets', '=', $noOfAssets);
        }

        return $newHires;
    }

    /**
     * Taking the asset assigned/loaned  latest history details
     * 
     * @param $userId App\User id
     * @return App\Models\AssetHistory
     */
    public function getAssignedOrLoanedLatestHistory($userId)
    {
        $history = AssetHistory::with(['user'])
            ->whereHas('asset', function ($query) use ($userId) {
                $query->hasAssetType('laptop')->hasAnyAssetStatus(['assigned', 'loaned']);
                $query->where('user_id', $userId);
            })->where('new_user_id', $userId)
            ->where('action', 'status_updated')
            ->whereIn('new_value', ['Assigned', 'Loaned'])
            ->latest()
            ->first();

        return $history;
    }


    /**
     * It returns the number of users who have been terminated in a given month.
     * 
     * @param firstDay The first day of the month
     * @param lastDay The last day of the month.
     * @return count of terminated users
     */
    public function getTerminatedUserCountByMonth($firstDay, $lastDay)
    {
        $terminationCount = User::whereBetween('terminated_date', [
            $firstDay, $lastDay
        ])
            ->where('status', '!=', 1)
            ->count();
        return  $terminationCount;
    }

    /**
     * It returns the count ofactive users who were hired before the last day of the month.
     * @param lastDay The last day of the month.
     * @return Count active users
     */
    public function getAciveUserCountByMonth($lastDay)
    {
        return User::whereDate('hire_date', '<=', $lastDay)
            ->where('status',  1)
            ->count();
    }

    /**
     * It gets the count of terminated fulltime users and their assets between two dates
     * 
     * @param fromDate The start date of the date range.
     * @param toDate The date to which you want to get the data.
     * @return $query
     */
    public function getTerminatedFteUsersAndAssetsCount($fromDate, $toDate)
    {
        $users = User::where('status', '!=', 1)
            ->whereBetweenTerminatedDate($fromDate, $toDate)
            ->withCount('assets');
        return $this->getFteUsers($users);
    }

    /**
     * It gets the count of terminated external users and their assets between two dates
     * @param fromDate The start date of the date range.
     * @param toDate The date to which you want to get the data.
     * @return $query
     */
    public function getTerminatedExtUsersAndAssetsCount($fromDate, $toDate)
    {
        $users = User::where('status', '!=', 1)
            ->whereBetweenTerminatedDate($fromDate, $toDate)
            ->withCount('assets');
        return $this->getExtUsers($users);
    }

    /**
     * It returns the number of fulltime users who have been hired between two dates and  are not BPO employees and number of destops or laptops assigned to them
     * @param fromDate The start date of the date range.
     * @param toDate The date to which you want to get the data.
     * @return $query
     */
    public function  getNewHireFteUsersAndAssetsCount($fromDate, $toDate)
    {
        $fromDate = $fromDate ? $fromDate : Carbon::now()->toDateTimeString();
        $users =  User::superAdmin()
            ->countDesktopOrLaptopAssigned()
            ->where('hire_date', '>=', $fromDate);

        if ($toDate) {
            $users->where('hire_date', '<=', $toDate);
        }
        return $this->getFteUsers($users)->get();
    }

    /**
     * It returns the number of external users who have been hired between two dates, are not BPO employees and number of destops or laptops assigned to them
     * @param fromDate The start date of the date range.
     * @param toDate The date to which you want to get the data.
     * @return $query
     */
    public function getNewHireExtUsersAndAssetsCount($fromDate, $toDate)
    {
        $fromDate = $fromDate ? $fromDate : Carbon::now()->toDateTimeString();
        $users =  User::superAdmin()
            ->countDesktopOrLaptopAssigned()
            ->where('hire_date', '>=', $fromDate);
        if ($toDate) {
            $users->where('hire_date', '<=', $toDate);
        }
        return   $this->getExtUsers($users)->get();
    }

    /**
     * Gets the full time employees
     * @param mixed $assets
     * 
     * @return [type]
     */
    public function getFteUsers($users)
    {
        $users = $users->where(function ($query) {
            $query->where('email', 'like', '%' . config('mail.fte_mail_domain'))
                ->whereRaw('LENGTH(employee_id) < 8');
        });


        return $users;
    }

    /**
     * Gets the third party users.
     * @param mixed $users
     * 
     * @return [type]
     */
    public function getExtUsers($users)
    {
        $users = $users->where(function ($query) {
            $query->where('email', 'not like', '%' . config('mail.fte_mail_domain'))
                ->orWhereRaw('LENGTH(employee_id) > 7');
        });

        return $users;
    }
}
