<?php

namespace App\Http\Traits;

use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
use Illuminate\Http\Request;
use DOMDocument;

trait CommonTrait
{
    /*
     * 비밀번호 확인 여부
     */
    public function isCertified(Request $request)
    {
        if (!$request->session()->exists('is-certified')) {
            return redirect()->route('account.certify')->with([
                'url' => urlencode($request->fullUrl())
            ])->send();
        }
    }

    /*
     * 비밀번호가 일치하는지 여부
     */
    public function passwordAuthed(string|null $plainPassword): bool
    {
        if ($plainPassword) {
            $hashPassword = Auth::user()->getAuthPassword();
            if (Hash::check($plainPassword, $hashPassword)) {
                return true;
            }
        }
        return false;
    }

    /*
     * 비밀번호 생성
     */
    public function passwordMake(string $plainPassword): string
    {
        return Hash::make($plainPassword);
    }

    /*
     * SNS 시간 표시
     */
    public function dateFormat($datetime, $format = null): string
    {
        $diff = time() - strtotime($datetime);

        $s = 60; // 1분 = 60초
        $h = $s * 60; // 1시간 = 60분
        $d = $h * 24; // 1일 = 24시간
        $y = $d * 10; // 1년 = 1일 * 10일

        if ($diff < $s) {
            $ret = $diff . '초전';
        } elseif ($h > $diff && $diff >= $s) {
            $ret = round($diff / $s) . '분전';
        } elseif ($d > $diff && $diff >= $h) {
            $ret = round($diff / $h) . '시간전';
        } elseif ($y > $diff && $diff >= $d) {
            $ret = round($diff / $d) . '일전';
        } else {
            if ($format) {
                $ret = now()->setTimeFromTimeString($datetime)->format($format);
            } else {
                $ret = date('Y.m.d H:i:s', strtotime($datetime));
            }
        }

        return $ret;
    }

    /*
     * Editor 동영상 개수 조회
     */
    public function getVideoRows(string $html): int
    {
        $dom = new DOMDocument('1.0', 'UTF-8');
        libxml_use_internal_errors(true);
        $dom->loadHTML('<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>' . $html);
        libxml_clear_errors();

        return ($dom->getElementsByTagName('iframe')->length + $dom->getElementsByTagName( "video" )->length);
    }

    /*
     * Editor 이미지 개수 조회
     */
    public function getImageRows(string $html): int
    {
        $dom = new DOMDocument('1.0', 'UTF-8');
        libxml_use_internal_errors(true);
        $dom->loadHTML('<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>' . $html);
        libxml_clear_errors();

        return $dom->getElementsByTagName('img')->length;
    }

    /*
     * 글자 자르기
     */
    public function strCut(string $str, int $limit, string $end = '...'): string
    {
        return ($limit > 0 ? \Illuminate\Support\Str::limit($str, $limit, $end) : $str);
    }

    /*
     * IP 를 정한 형식에 따라 보여주기
     */
    public function ipAddrMasking(string $ip, string $type = '0001'): string
    {
		$len = strlen($type);
		if ($len !== 4) {
			return $ip;
		}
		if (empty($ip)) {
			return $ip;
		}

		$regex = ($type[0] === '1') ? '\\1' : '&#9825;';
		$regex .= '.';
		$regex .= ($type[1] === '1') ? '\\2' : '&#9825;';
		$regex .= '.';
		$regex .= ($type[2] === '1') ? '\\3' : '&#9825;';
		$regex .= '.';
		$regex .= ($type[3] === '1') ? '\\4' : '&#9825;';

		return preg_replace("/([0-9]+).([0-9]+).([0-9]+).([0-9]+)/", $regex, $ip);
    }

    /*
     * 자동 URL 링크 생성
     */
    public function urlAutoLink(string $str = "", bool $popup = false): string
	{
        $target = ($popup ? 'target="_blank"' : '');
        $str = str_replace(["<", ">", "&amp;", "&quot;", " ", "&#039;"], ["\t_lt_\t", "\t_gt_\t", "&", "\"", "\t_nbsp_\t", "'"], $str);
        $str = preg_replace("/([^(href=\"?'?)|(src=\"?'?)]|\(|^)((http|https|ftp|telnet|news|mms):\/\/[a-zA-Z0-9\.-]+\.[가-힣\xA1-\xFEa-zA-Z0-9\.:&#=_\?\/~\+%@;\-\|\,\(\)]+)/i", "\\1<a href=\"\\2\" {$target}>\\2</A>", $str);
        $str = preg_replace("/(^|[\"'\s(])(www\.[^\"'\s()]+)/i", "\\1<a href=\"http://\\2\" {$target}>\\2</A>", $str);
        $str = preg_replace("/[0-9a-z_-]+@[a-z0-9._-]{4,}/i", "<a href=\"mailto:\\0\">\\0</a>", $str);
        return str_replace(["\t_nbsp_\t", "\t_lt_\t", "\t_gt_\t", "'"], [" ", "<", ">", "&#039;"], $str);
	}

	/*
	 * Image, iframe, video Thumbnail 저장
	 */
	public function getThumbnail(string $html, ?string $defaultImgSrc = null): ?string
    {
        preg_match_all("/<img[^>]*src=[\"']?([^>\"']+)[\"']?[^>]*>/i", $html, $matches);

        if(array_key_exists(1, $matches)) {
            return current($matches[1]) ?: null;
        }

        $iframeVideoSrc = $this->getYoutubeKey(getIframeTag($html, true)); // iframe src 추출
        if($iframeVideoSrc) {
            return sprintf("https://img.youtube.com/vi/%s/mqdefault.jpg", $iframeVideoSrc);
        }

        return (file_exists($defaultImgSrc) ? url($defaultImgSrc) : null);
    }

    /**
     * Youtube 썸네일 경로 조회
     */
    public function getYoutubeThumbURL(?string $str, int $type): string
    {
        $result = "";
        $youTubeId = $this->getYoutubeKey($str);
        if ($youTubeId) {
            switch ($type) {
                default :
                case 1 : // default
                    $size = 'default';
                    break;
                case 2 : // High Quality Thumbnail
                    $size = 'hqdefault';
                    break;
                case 3 : // Medium Quality
                    $size = 'mqdefault';
                    break;
                case 4 :  // Standard Definition
                    $size = 'sddefault';
                    break;
                case 5 :  // Maximum Resolution
                    $size = 'maxresdefault';
                    break;
            }
            $result = sprintf("//img.youtube.com/vi/%s/%s.jpg", $youTubeId, $size);
        }
        return $result;
    }

    /**
     * Youtube 퍼가기 URL 조회
     */
    public function getYoutubeEmbedUrl(?string $str): string
    {
        $result = "";
        $youTubeId = $this->getYoutubeKey($str);
        if ($youTubeId) {
            $result = sprintf("//www.youtube.com/embed/%s", $youTubeId);
        }
        return $result;
    }

    /*
     * Youtube Video ID 조회
     */
    public function getYoutubeKey(?string $src)
    {
        preg_match('#(?<=(?:v|i)=)[a-zA-Z0-9-]+(?=&)|(?<=(?:v|i)\/)[^&\n]+|(?<=embed\/)[^"&\n]+|(?<=‌​(?:v|i)=)[^&\n]+|(?<=youtu.be\/)[^&\n]+#', $src, $matches);
        return array_pop($matches);
    }

    /*
     * 이모티콘 삭제
     */
    public function removeEmoji(string $t): string
    {
        return iconv('ISO-8859-15', 'UTF-8', preg_replace('/\s+/', ' ', iconv('UTF-8', 'ISO-8859-15//IGNORE', $t)));
    }

    /*
     * 숫자만 조회
     */
    public function getOnlyNumber(string $str): array|null
    {
        return preg_replace('/[^0-9]/', '', $str);
    }

    /*
     * 금액을 한글로 변환
     */
    public function numberToHangul($number): string
    {
        $num = ['', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
        $unit4 = ['', '만', '억', '조', '경'];
        $unit1 = ['', '십', '백', '천'];
        $res = [];
        $number = str_replace(',', '', $number);
        $split4 = str_split(strrev(strval($number)), 4);

        for ($i = 0; $i < count($split4); $i++) {
            $temp = [];
            $split1 = str_split(strval($split4[$i]), 1);
            for ($j = 0; $j < count($split1); $j++) {
                $u = intval($split1[$j]);
                if ($u > 0) {
                    $temp[] = $num[$u] . $unit1[$j];
                }
            }
            if (count($temp) > 0) {
                $res[] = implode('', array_reverse($temp)) . $unit4[$i];
            }
        }
        return implode('', array_reverse($res));
    }

    /**
     * Unique 반환
     */
    public function makeUniqueKey(int $length): string
    {
        return Str::random($length);
    }

    /**
     * 회원 프로필 이미지 조회
     */
    public function profileThumbSrc(?string $imgPath): string
    {
        return ($imgPath) ? asset($imgPath) : asset(NO_IMAGE_THUMB_SRC);
    }

    /*
     * 배열에 작은 따옴표를 추가한다. WHERE IN 사용시 편함
     */
    public function setArraySingQuote(array $arr)
    {
        return implode(', ', array_map(function ($val) {return sprintf("'%s'", $val);}, $arr));
    }

    /**
     * 에디터 내용안에서 이미지 주소를 찾아내 삭제한다.
     */
    public function deleteImageFromContent(?string $content): string
    {
        $dom = new DOMDocument('1.0', 'UTF-8');
        libxml_use_internal_errors(true);
        $dom->loadHTML('<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>' . $content);
        libxml_clear_errors();

        foreach ($dom->getElementsByTagName('img') as $img) {
            $filePath = public_path($img->attributes->getNamedItem("src")?->value);

            if (file_exists($filePath)) {
                unlink($filePath);
            }

            $img->parentNode->removeChild($img);
        }

        unset($content);

        return $dom->saveHTML();
    }

    /**
     * OpenSSL 암호화
     */
    public function sslEncrypt(string $s): string
    {
        return base64_encode(openssl_encrypt($s, "AES-128-CBC", openssl_digest(ENCRYPT_KEY, 'MD5', true), OPENSSL_ENCODING_DER, substr(md5(ENCRYPT_IV), 0, 16)));
    }

    /**
     * OpenSSL 복호화
     */
    public function sslDecrypt(string $s): string
    {
        return openssl_decrypt(base64_decode($s), "AES-128-CBC", openssl_digest(ENCRYPT_KEY, 'MD5', true), OPENSSL_ENCODING_DER, substr(md5(ENCRYPT_IV), 0, 16));
    }

    /**
     * 환율 조회
     */
    protected function callExchangeData(string $date = null): ?array
    {
        if (!$ret = cache('exchange-' . $date)) {
            $ret = \Illuminate\Support\Facades\Http::get('https://www.koreaexim.go.kr/site/program/financial/exchangeJSON', [
                'authkey' => KOREA_EXIM_AUTH_KEY,
                'searchdate' => ($date ?? null),
                'data' => 'AP01'
            ]);
            if ($ret->ok()) {
                $ret = $ret->object();
                cache([('exchange-' . $date) => $ret]);
            }
        }
        return $ret;
    }
}