<?php

namespace App\Http\Controllers\Admin;

use App\Facades\RequestContext;
use App\Http\Controllers\Controller;
use App\Http\Requests\BusinessCardStore;
use App\Libs\Services\BackendUserService;
use Illuminate\Http\Request;
use Spatie\Fractal\Facades\Fractal;
use App\Libs\Services\BusinessCardService;
use App\Libs\Transformers\BusinessCard\BusinessCardTransformer;
use App\Models\BusinessCard;
use chillerlan\QRCode\Output\QRGdImagePNG;
use chillerlan\QRCode\Output\QROutputInterface;
use chillerlan\QRCode\QRCode;
use chillerlan\QRCode\QROptions;
use Illuminate\Support\Str;

class BusinessCardController extends Controller
{
    use UserManageTrait;

    public function getIndex(BackendUserService $backendUserService)
    {
        $loggedUser = $backendUserService->getLoggedUser();

        return view('admin.pages.business_cards.business_cards', [
            'canInsert'     => $loggedUser->hasPermission('users.insert'),
            'loggedUser'    => $loggedUser,
        ]);
    }

    public function postList(Request $request, BusinessCardService $businessCardService)
    {
        $page = $request->input("current");
        $rowCount = $request->input("rowCount");
        $sort = $request->input("sort");
        $search = $request->input("searchPhrase");

        if (!empty($page)) {
            $result = $businessCardService->getBusinessCardGridList($page, $rowCount, $sort, $search);
            $result["rows"] = Fractal::collection($result["rows"])
                ->transformWith(new BusinessCardTransformer())->toArray();

            return response()->json($result);
        } else {
            $businessCards = BusinessCard::all();
            return response()->json(Fractal::collection($businessCards)
                ->transformWith(new BusinessCardTransformer())->toArray());
        }
    }

    public function getEdit($businessCardId = null)
    {
        $loggedUser = BackendUserService::getLoggedUser();

        if (!empty($businessCardId) && $loggedUser->id != $businessCardId
            && !$loggedUser->hasPermission("users.view")
            && !$loggedUser->hasPermission("users.insert")) {
            abort(403);
        }

        $canManage = $this->_canManage($businessCardId);
        $canEdit   = $this->_canEdit($businessCardId);

        RequestContext::set('selected_menu', 'admin');
        RequestContext::set('selected_menu_option', 'list_users');

        if (!empty($businessCardId)) {
            $businessCard = BusinessCard::find($businessCardId);
        } else {
            $businessCard = new BusinessCard();
        }

        if(empty($businessCard)){
            abort(404);
        }

        return view('admin.pages.business_cards.business_card_form', [
            'businessCard'   => $businessCard,
            'canManage'      => $canManage,
            'canEdit'        => $canEdit,
            'canView'        => $loggedUser->hasPermission("users.view")
        ]);
    }

    public function postEdit(BusinessCardStore $request, BusinessCardService $businessCardService, $businessCardId = null)
    {
        $data = $request->validated();

        if(!empty($businessCardId)){
            $businessCard = $businessCardService->editBusinessCard($businessCardId, $data);
            $message = "Business Card updated";
        } else {
            $businessCard = $businessCardService->createBusinessCard($data);
            $message = "Business Card created";
        }

        return redirect('/admin/admin-business-cards/edit/' . $businessCard->id)
            ->with("message", $message);
    }

    public function postDelete(Request $request)
    {
        $id = $request->input("id");
        $businessCard = BusinessCard::find($id);

        if(!empty($businessCard)) {
            $businessCard->delete();
        }

        return response()->json(["success" => true]);
    }

    public function getDownloadQRCode(Request $request)
    {
        $businessCardId = $request->input("businessCardId");
        $businessCard = BusinessCard::find($businessCardId);
        $slug = $businessCard->slug;

        if (!empty($slug)) {
            $url = config('app.url_frontend') . "/digital-business-card/" . $slug;

            $options = new QROptions([
                'outputType' => QROutputInterface::GDIMAGE_PNG,
                'outputBase64' => false,
                'scale'        => 10,
            ]);

            // $qrcode = (new QRCode($options))->render($url);
            $qrcode = (new QRCode($options))->addByteSegment($url);
            $qrOutputInterface = new QRImageWithText($options, $qrcode->getQRMatrix());
            $out = $qrOutputInterface->dump(null, $businessCard->name);

            $filename = Str::slug($businessCard->name) . '-qrcode.png';

            return response($out)
                ->header('Content-Type', 'image/png')
                ->header('Content-Disposition', "attachment; filename=\"{$filename}\"");
        }

        return response()->json(['error' => 'Slug not found'], 404);
    }

    public function postCheckSlug()
    {
        $originSlug = request()->input("slug");

        if (empty($originSlug)) {
            return response()->json(array(
                "error" => "bad_syntax",
                "description" => "The request is missing the slug"
            ), 400);
        }

        $originSlug = urlize($originSlug);
        $slug = $originSlug;

        $slugCounter = 1;
        while (BusinessCard::hasSlug($slug) && $slugCounter <= 100) {
            $slug = $originSlug."-".$slugCounter;
            $slugCounter++;
        }

        if ($slugCounter == 100) {
            $slug = false;
        }

        if ($slug === false) {
            return response()->json(array(
                "error" => "invalid",
                "description" => "Impossible to generate this slug"
            ), 400);
        } else {
            return response()->json(array("slug" => $slug));
        }
    }
}

class QRImageWithText extends QRGdImagePNG {

	public function dump(string|null $file = null, string|null $text = null):string{
		// set returnResource to true to skip further processing for now
		$this->options->returnResource = true;

		// there's no need to save the result of dump() into $this->image here
		parent::dump($file);

		// render text output if a string is given
		if($text !== null){
			$this->addText($text);
		}

		$imageData = $this->dumpImage();

		$this->saveToFile($imageData, $file);

		if($this->options->outputBase64){
			$imageData = $this->toBase64DataURI($imageData);
		}

		return $imageData;
	}

	protected function addText(string $text):void{
		// save the qrcode image
		$qrcode = $this->image;

		// options things
		$textSize  = 3; // see imagefontheight() and imagefontwidth()
		$textBG    = [200, 200, 200];
		$textColor = [50, 50, 50];

		$bgWidth  = $this->length;
		$bgHeight = ($bgWidth + 20); // 20px extra space

		// create a new image with additional space
		$this->image = imagecreatetruecolor($bgWidth, $bgHeight);
		$background  = imagecolorallocate($this->image, ...$textBG);

		// allow transparency
		if($this->options->imageTransparent){
			imagecolortransparent($this->image, $background);
		}

		// fill the background
		imagefilledrectangle($this->image, 0, 0, $bgWidth, $bgHeight, $background);

		// copy over the qrcode
		imagecopymerge($this->image, $qrcode, 0, 0, 0, 0, $this->length, $this->length, 100);
		imagedestroy($qrcode);

		$fontColor = imagecolorallocate($this->image, ...$textColor);
		$w         = imagefontwidth($textSize);
		$x         = round(($bgWidth - strlen($text) * $w) / 2);

		// loop through the string and draw the letters
		foreach(str_split($text) as $i => $chr){
			imagechar($this->image, $textSize, (int)($i * $w + $x), $this->length, $chr, $fontColor);
		}
	}

}
