<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Traits\TossTrait;
use App\Http\Traits\CryptTrait;
use App\Models\Config;
use App\Models\User;
use App\Models\DTO\ResponseData;
use App\Models\DTO\Toss\AuthData;
use App\Models\DTO\Toss\FailData;
use App\Rules\DeniedEmail;
use App\Rules\SpecialCharLength;
use App\Rules\UppercaseLength;
use App\Rules\NumberLength;
use App\Rules\AllowNickname;
use App\Rules\IsPhone;
use Exception;

class ApiController extends Controller
{
    use TossTrait, CryptTrait;

    public function __construct()
    {
    }

    /**
     * 로그인 확인
     */
    public function loginCheck(): int
    {
        return intval(auth()->check());
    }

    /**
     * 금지 단어 확인
     */
    public function filterSpamKeyword(Request $request, ResponseData $response): ResponseData
    {
        $subject = $request->input('subject');
        $content = $request->input('content');
        $response->subject = "";
        $response->content = "";
        $spamWord = explode(',', trim((new Config)->item("spam_word")));

        if ($spamWord) {
            for ($i = 0; $i < count($spamWord); $i++) {
                $str = trim($spamWord[$i]);
                if ($subject) {
                    $pos = stripos($subject, $str);
                    if ($pos !== false) {
                        $response->subject = $str;
                        break;
                    }
                }
                if ($content) {
                    $pos = stripos($content, $str);
                    if ($pos !== false) {
                        $response->content = $str;
                        break;
                    }
                }
            }
        }

        return $response;
    }

    /**
     * 중복 이메일 여부
     */
    public function isEmailAble(Request $request): bool
    {
        try {

            $email = $request->input('email');
            if (!$email) {
                throw new Exception;
            }

            // 중복 여부
            if ((new User)->where('email', $email)->exists()) {
                throw new Exception;
            }

            // 유효성 확인
            if (!(new DeniedEmail)->passes(null, $email)) {
                throw new Exception;
            }

            return true;
        } catch (Exception) {
            return false;
        }
    }

    /**
     * 비밀번호 유효성 검사
     */
    public function isPasswordAble(Request $request): bool
    {
        try {

            $password = $request->input('password');
            if (!$password) {
                throw new Exception;
            }

            // 유효성 확인
            if (!(new SpecialCharLength)->passes(null, $password)) {
                throw new Exception;
            }

            if (!(new UppercaseLength)->passes(null, $password)) {
                throw new Exception;
            }

            if (!(new NumberLength)->passes(null, $password)) {
                throw new Exception;
            }

            return true;
        } catch (Exception) {
            return false;
        }
    }

    /**
     * 중복 닉네임 여부
     */
    public function isNicknameAble(Request $request): bool
    {
        try {

            $nickname = $request->input('nickname');
            if (!$nickname) {
                throw new Exception;
            }

            // 중복 여부
            if ((new User)->where('nickname', $nickname)->exists()) {
                throw new Exception;
            }

            // 유효성 확인
            if (!(new AllowNickname)->passes(null, $nickname)) {
                throw new Exception;
            }

            return true;
        } catch (Exception) {
            return false;
        }
    }

    /**
     * 중복 휴대전화번호 유효성 검사
     */
    public function isPhoneAble(Request $request): bool
    {
        try {

            $phone = $request->input('phone');
            if (!$phone) {
                throw new Exception;
            }

            // 중복 여부
            if ((new User)->where('phone', $phone)->exists()) {
                throw new Exception;
            }

            // 유효성 확인
            if (!(new IsPhone)->passes(null, $phone)) {
                throw new Exception;
            }

            return true;
        } catch (Exception) {
            return false;
        }
    }


    /**
     * 정기 비밀번호 변경 다음에 하기
     */
    public function passwordCampaignSkip()
    {
        return (new User)->where('id', UID)->update([
            'password_updated_at' => now()
        ]);
    }

    /**
     * TinyMCE 에디터 이미지 첨부 화면
     */
    public function uploader()
    {
        return view('component.uploader');
    }

    /**
     * 토스 본인확인 요청 (푸쉬앱)
     */
    public function requestTossCertToPush(Request $request)
    {
        try {

            $posts = $request->validate([
                'name' => 'required|string|min:2|max:10',
                'birthday' => 'required|digits:8',
                'phone' => 'required|numeric|unique:users'
            ], [
                'name.required' => '이름을 입력해주세요.',
                'name.string' => '이름 형식이 옳지 않습니다.',
                'name.min' => '이름은 최소 2자 이상 입력해주세요.',
                'name.max' => '이름은 최대 10자 입력 가능합니다.',
                'birthday.required' => '생년월일을 입력해주세요.',
                'birthday.digits' => '생년월일 형식이 옳지 않습니다.',
                'phone.required' => '휴대전화를 입력해주세요.',
                'phone.numeric' => '휴대전화번호는 숫자(`-` 없이)만 입력해주세요.',
                'phone.unique' => '이미 사용 중인 휴대전화입니다.'
            ], [
                'name' => '이름',
                'birthday' => '생년월일',
                'phone' => '휴대전화'
            ]);

            $sessionId = $this->generateSessionId();
            $secretKey = $this->generateRandomBytes(32);
            $iv = $this->generateRandomBytes(12);
            $sessionKey = $this->generateSessionKey($sessionId, $secretKey, $iv);

            $name = $this->encryptData($sessionId, $secretKey, $iv, $posts['name']);
            $birthday = $this->encryptData($sessionId, $secretKey, $iv, $posts['birthday']);
            $phone = $this->encryptData($sessionId, $secretKey, $iv, $posts['phone']);

            $token = $this->requestAccessToken($request);
            $result = $this->requestUserAuth($token, new AuthData(
                'USER_PERSONAL', 'PUSH', $name, $phone, $birthday, $sessionKey
            ));

            return response()->json($result)->withCookie(
                'tossAccessToken', serialize($token), ($token['expires_in'] / 60)
            );
        }catch(Exception $e) {
            return new FailData($e->getCode(), $e->getMessage());
        }
    }

    /**
     * 토스 본인확인 요청 (표준창)
     */
    public function requestTossCertToPopup(Request $request)
    {
        try {

            $token = $this->requestAccessToken($request);
            $result = $this->requestUserAuth($token, new AuthData('USER_NONE'));

            return response()->json($result)->withCookie(
                'tossAccessToken', serialize($token), ($token['expires_in'] / 60)
            );
        }catch(Exception $e) {
            return new FailData($e->getCode(), $e->getMessage());
        }
    }

    /**
     * 토스 본인확인 상태 검증
     */
    public function requestTossCertStatus(Request $request)
    {
        try {

            $posts = $request->validate([
                'tx_id' => 'required',
            ], [
                'tx_id.required' => '비 정상적인 접근입니다.'
            ], [
                'tx_id' => 'TXID'
            ]);

            $token = $this->requestAccessToken($request);

            return response()->json(
                $this->requestUserAuthStatus($token, $posts['tx_id'])
            );
        }catch(Exception $e) {
            return new FailData($e->getCode(), $e->getMessage());
        }
    }
}
