<?php

namespace App\Http\Controllers;

use Exception;
use Validator;
use Carbon\Carbon;
use App\Models\License;
use App\Models\MacDetail;
use Illuminate\Http\Request;
use App\Models\LicenseLedger;
use App\Models\LicenseMacMapping;
use Illuminate\Support\Facades\DB;
use App\Exceptions\GeneralException;

/**
 * Class LanguageController.
 */
class ApiLicenseController extends Controller
{
    public function __construct()
    {
        $this->middleware(['api_auth', 'verify_license']);
    }

    /**
     * @param $locale
     *
     * @return \Illuminate\Http\RedirectResponse
     */
    // public function verifyLicense(LicenseVerificationRequest $request)
    // {
    //     try {
    //         $headerVerification = $request->header('Authorization');
    //         $licenseKey = $request->input('licenseKey');
    //         $macId = $request->input('macId');
    //         $Ipaddress = $request->input('ipAddress');

    //         if ($headerVerification === config('license.authKey')) {
    //             $verifyStatus = $this->checkLicense($licenseKey, $macId, $Ipaddress);

    //             return response()->json([
    //                 'message' => $verifyStatus,
    //                 'status' => 200,
    //             ], 200);
    //         }

    //         return response()->json([
    //             'message' => 'unauthorized',
    //             'status' => 401,
    //         ], 200);
    //     } catch (Exception $ex) {
    //         return response()->json([
    //             'message' => $ex->getMessage(),
    //             'status' => 401,
    //         ], 400);
    //     }
    // }

    // public function checkLicense($licenseKey, $macId, $Ipaddress)
    // {
    //     $statusMessage = 'invalidkey';
    //     $status = 0;
    //     $freshLicence = false;

    //     $result = [
    //         'message' => $statusMessage,
    //         'status' => 500,
    //     ];

    //     $license = License::where([['key_uuid', $licenseKey]])->first();

    //     if ($license == null) {
    //         throw new GeneralException(__('exceptions.backend.access.licensekeynotfound'));
    //     }

    //     if ($license->status === 'inactive') {
    //         throw new GeneralException(__('exceptions.backend.access.licenseKeyDeactivated'));
    //     }

    //     if (MacDetail::whereMacUuib($macId)->whereDisabled(true)->exists()) {
    //         throw new GeneralException(__('exceptions.backend.access.mac.disabledAddress'));
    //     }

    //     $macDetail = MacDetail::where([['mac_uuib', $macId]])->first();

    //     $licenseMacMappingquery = LicenseMacMapping::with(['License', 'MacDetail'])
    //         ->where([['lincensekeyId', $license->id]]);

    //     $licenseMacMapping = ($macDetail != null)
    //     ? $licenseMacMappingquery
    //         ->where([['macDetailId', $macDetail->id]])
    //         ->orderBy('id', 'desc')
    //         ->first()
    //     : $licenseMacMappingquery
    //         ->orderBy('id', 'desc')
    //         ->first();

    //     if ($licenseMacMapping && $licenseMacMapping->mac_status === 'inactive') {
    //         throw new GeneralException(__('exceptions.backend.access.mac.inactiveAddress'));
    //     }

    //     //if new licence and mac
    //     if ($licenseMacMapping == null) {
    //         $licenseMacMapping = DB::transaction(function () use ($macId,$license,&$macDetail, &$freshLicence) {
    //             if ($macDetail == null) {
    //                 $macDetail = MacDetail::create([
    //                     'mac_uuib' => $macId,
    //                     'userId' => $license->licenseUserId,
    //                     'status' => 'active',
    //                 ]);
    //             }

    //             $licenseMac = LicenseMacMapping::create([
    //                 'lincensekeyId' => $license->id,
    //                 'macDetailId' => $macDetail->id,
    //                 'allocatedUserId' => $license->licenseUserId,
    //                 'license_key_status' => 'active',
    //                 'mac_status' => 'active',
    //             ]);

    //             $freshLicence = true;

    //             return $licenseMac;
    //         });
    //         $statusMessage = 'activated';
    //     }

    //     //allocate old license key with new one
    //     if (($licenseMacMapping != null) && ($macDetail == null) && ($licenseMacMapping->mac_status == 'inactive')) {
    //         DB::transaction(function () use ($macId,$license,&$macDetail) {
    //             if ($macDetail == null) {
    //                 $macDetail = MacDetail::create([
    //                     'mac_uuib' => $macId,
    //                     'userId' => $license->licenseUserId,
    //                     'status' => 'active',
    //                 ]);
    //             }

    //             $licenseMac = LicenseMacMapping::create([
    //                 'lincensekeyId' => $license->id,
    //                 'macDetailId' => $macDetail->id,
    //                 'allocatedUserId' => $license->licenseUserId,
    //                 'license_key_status' => 'active',
    //                 'mac_status' => 'active',
    //             ]);
    //         });
    //         $statusMessage = 'reActivated';
    //     }
    //     //already activated
    //     if (($licenseMacMapping != null)
    //         && ($macDetail != null)
    //         && ($licenseMacMapping->mac_status == 'active')
    //         && (! $freshLicence)) {
    //         $statusMessage = 'alreadyActivated';
    //     }

    //     //wrong mac key
    //     //already activated
    //     if (($licenseMacMapping != null) && ($macDetail == null) && ($licenseMacMapping->mac_status == 'active') && (! $freshLicence)) {
    //         $result = [
    //             'message' => 'anotherMacKeyAdded',
    //             'status' => 400,
    //         ];
    //     }
    //     // add the ledger
    //     if ($macDetail != null) {
    //         $licenseledger = LicenseLedger::create([
    //             'lincensekeyId' => $license->id,
    //             'macDetailId' => $macDetail->id,
    //             'ipAddress' => $Ipaddress,
    //             'apiStatus' => $statusMessage,
    //         ]);

    //         $result = [
    //             'message' => $statusMessage,
    //             'duration' => $license->licenseTypeDetails->duration,
    //             'licenseType' => $license->licenseTypeDetails->licence_type,
    //             'status' => ($status == 0) ? 200 : 400,
    //             'startDate' => Carbon::parse($licenseMacMapping->created_at)->format('d-m-Y'),
    //         ];

    //         $result['expiryDate'] = $license->licenseTypeDetails->duration
    //             ? Carbon::parse($licenseMacMapping->created_at)
    //                 ->addDays($license->licenseTypeDetails->duration)
    //                 ->format('d-m-Y')
    //             : null;
    //     }

    //     return $result;
    // }

    /**
     * verify license and mac details
     * 
     * @author Jansen N. J <jansen@riolabz.com>
     */
    public function verifyLicense(Request $request)
    {
        $validation = Validator::make($request->all(), [
            'licenseKey' => 'required',
            'macId' => 'required',
            'ipAddress' => 'required|ip',
        ]);

        if ($validation->fails()) {
            return $this->errorResponse(__('exceptions.backend.access.validationError'));
        }

        $license = License::where('key_uuid', $request->licenseKey)->first();
        
        // license is not valid
        if (! $license) {
            return $this->errorResponse(__('exceptions.backend.access.licensekeynotfound'));
        }

        $macAddress = MacDetail::firstOrCreate(
            ['mac_uuib' => $request->macId],
            [
                'userId' => $license->licenseUserId,
                'status' => 'active',
            ]
        );

        // inactive license
        if ($license->status === 'inactive') {
            return $this->errorResponse(__('exceptions.backend.access.licenseKeyDeactivated'));
        }

        // disabled license
        if ($macAddress->disabled) {
            return $this->errorResponse(__('exceptions.backend.access.mac.disabledAddress'));
        }

        $verificationStatus = $this->checkLicense($license, $macAddress);

        return response()->json([
            'message' => $verificationStatus,
            'status' => $verificationStatus['status'],
        ], $verificationStatus['status']);
    }

    /**
     * checks if payload can be verified against the license.
     *
     * @author Jansen N. J <jansen@riolabz.com>
     */
    public function checkLicense(License $license, MacDetail $macAddress): array
    {
        $macMappings = $macAddress->mappings()->get();

        $licenseMappings = $license->licensemacMapping()->get();

        // key activation
        if ($macMappings->isEmpty() && $licenseMappings->isEmpty()) {
            $this->createMapping($license, $macAddress);

            return $this->success($license, $macAddress, __('license.verification.activated'));
        }

        $activatedWithAnyOtherLicense = $macMappings
            ->filter(
                function ($mapping) use ($license) {
                    return $license->id !== $mapping->lincensekeyId
                    && $mapping->mac_status === 'active';
                }
            );
        
        // checks if key is active for any other license
        if ($activatedWithAnyOtherLicense->isNotEmpty()) {
            return $this->error(__('license.verification.usedMacAddress'));
        }

        // if accessed with active mac for the license key
        if (
            $licenseMappings
                ->where('macDetailId', $macAddress->id)
                ->where('mac_status', 'active')
                ->isNotEmpty()
            ) {
            return $this->success($license, $macAddress, __('license.verification.reactivated'));
        }

        // checks if any activated mac exists for the license key
        if ($licenseMappings->where('mac_status', 'active')->isNotEmpty()) {
            return $this->error(__('license.verification.activationRecordsExists'));
        }

        // checks if the mac inactive for the license key
        if ($macMappings
            ->where('lincensekeyId', $license->id)
            ->where('mac_status', 'inactive')
            ->isNotEmpty()) {
            return $this->error(__('license.verification.macInactiveForTheLicense'));
        }

        $licenseMappingInactiveCount = $licenseMappings->where('mac_status', 'inactive')->count();

        // license re-activation when  all other macs for the license are on hold
        if ($licenseMappings->count() === $licenseMappingInactiveCount) {
            $this->createMapping($license, $macAddress);

            $macAddress->mappings()
                ->where('lincensekeyId', '!=', $license->id)
                ->update(
                    ['mac_status' => 'inactive']
                );

            return $this->success($license, $macAddress, __('license.verification.reactivatedWithNewMac'));
        }

        return $this->error('Unknown Error');
    }

    /**
     * emit success.
     *
     * @param License $license
     * @param MacDetail $macAddress
     * @param string $message
     * @author Jansen N. J <jansen@riolabz.com>
     */
    public function success(License $license, MacDetail $macAddress, string $message)
    {
        $lastMapping = $license->licensemacMapping()
            ->latest()
            ->first();

        return [
            'message' => $message,
            'duration' => $license->licenseTypeDetails->duration,
            'licenseType' => $license->licenseTypeDetails->licence_type,
            'status' => 200,
            'startDate' => Carbon::parse($lastMapping->created_at)->format('d-m-Y'),
            'expiryDate' => $license->licenseTypeDetails->duration
            ? Carbon::parse($lastMapping->created_at)
                ->addDays($license->licenseTypeDetails->duration)
                ->format('d-m-Y') : null,
        ];
    }

    /**
     * emit error.
     *
     * @param string $message
     * @author Jansen N. J <jansen@riolabz.com>
     */
    public function error(string $message)
    {
        return [
            'message' => $message,
            'status' => 400,
        ];
    }

    public function errorResponse(string $message)
    {
        return response()->json([
            'message' => $message,
            'status' => 400,
        ], 400);
    }

    /**
     * create mac, license mapping.
     *
     * @param License $license
     * @param MacDetail $macAddress
     */
    public function createMapping(License $license, MacDetail $macAddress)
    {
        return DB::transaction(function () use ($license, $macAddress) {
            return $license->licensemacMapping()->updateOrCreate(
                ['macDetailId' => $macAddress->id],
                [
                    'allocatedUserId' => $license->licenseUserId,
                    'license_key_status' => 'active',
                    'mac_status' => 'active',
                ]
            );
        });
    }
}
