# -*- coding:utf-8 -*-
import os
import random
import re
import ssl
import time
from urllib.request import urlretrieve

import undetected_chromedriver as uc
from PIL import Image
from lxml import etree
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait


class CrackGeetest():
    def __init__(self):
        self.url = 'https://gsxt.amr.jiangxi.gov.cn/indexmain.jsp?'
        self.company_name = "南昌银行"

    def chrome_operate(self):
        chrome_options = webdriver.ChromeOptions()
        # chrome_options.add_argument('--headless')
        chrome_options.add_argument('--no-sandbox')
        chrome_options.add_argument('--disable-gpu')
        chrome_options.add_argument('--lang=zh-CN')
        chrome_options.add_argument('--hide-scrollbars')
        # 禁止加载图片
        chrome_options.add_argument('blink-settings=imagesEnabled=false')
        # 指定浏览器分辨率
        chrome_options.add_argument('--start-maximized')
        ssl._create_default_https_context = ssl._create_unverified_context

        uc.TARGET_VERSION = 110  # 指定chrome版本
        self.browser = uc.Chrome(options=chrome_options)
        self.wait = WebDriverWait(self.browser, 10)
        self.browser.get(self.url)
        time.sleep(2)
        self.browser.find_element(By.XPATH, '//*[@id="entname"]').click()
        time.sleep(0.5)
        self.browser.find_element(By.XPATH, '//*[@id="entname"]').clear()
        time.sleep(0.5)
        self.browser.find_element(By.XPATH, '//*[@id="entname"]').send_keys(self.company_name)
        time.sleep(0.5)
        self.browser.find_element(By.XPATH, '//*[@id="serach"]').click()
        time.sleep(1)

    def mk_img_dir(self):
        """
        创建图片目录文件
        :return:
        """
        if not os.path.exists('../national_enterprise_credit/Image'):
            os.mkdir('../national_enterprise_credit/Image')

    def get_geetest_image(self):
        """
        获取验证码图片
        :return: 图片location信息
        """
        bg = []
        fullgb = []

        while bg == [] and fullgb == []:
            etree_html = etree.HTML(self.browser.page_source)
            bg = etree_html.xpath('//div[@class="gt_cut_bg_slice"]')
            fullgb = etree_html.xpath('//div[@class="gt_cut_fullbg_slice"]')
            # soup = BeautifulSoup(self.browser.page_source, 'lxml')
            # bg = soup.find_all('div', class_='gt_cut_bg_slice')
            # fullgb = soup.find_all('div', class_='gt_cut_fullbg_slice')

        bg_url = re.findall('url\(\"(.*?)\"\);', bg[0].get('style'))[0].replace('webp', 'jpg')
        fullgb_url = re.findall('url\(\"(.*?)\"\);', fullgb[0].get('style'))[0].replace('webp', 'jpg')
        bg_location_list = []
        fullgb_location_list = []

        for each_bg in bg:
            location = {}
            location['x'] = int(re.findall('background-position: (.*)px (.*)px;', each_bg.get('style'))[0][0])
            location['y'] = int(re.findall('background-position: (.*)px (.*)px;', each_bg.get('style'))[0][1])
            bg_location_list.append(location)

        for each_fullgb in fullgb:
            location = {}
            location['x'] = int(re.findall('background-position: (.*)px (.*)px;', each_fullgb.get('style'))[0][0])
            location['y'] = int(re.findall('background-position: (.*)px (.*)px;', each_fullgb.get('style'))[0][1])
            fullgb_location_list.append(location)

        self.mk_img_dir()
        urlretrieve(url=bg_url, filename='../national_enterprise_credit/Image/bg.jpg')
        print('缺口图片下载完成!')
        urlretrieve(url=fullgb_url, filename='../national_enterprise_credit/Image/fullgb.jpg')
        print('背景图片下载完成!')
        return bg_location_list, fullgb_location_list

    def get_merge_image(self, filename, location_list):
        """
        根据图片位置合并还原
        :param filename: 图片
        :param location: 位置
        :return:合并后的图片对象
        """
        im = Image.open(filename)
        new_im = Image.new('RGB', (260, 116))
        im_list_upper = []
        im_list_lower = []

        for location in location_list:
            if location['y'] == -58:
                im_list_upper.append(im.crop((abs(location['x']), 58, abs(location['x']) + 10, 116)))
            if location['y'] == 0:
                im_list_lower.append(im.crop((abs(location['x']), 0, abs(location['x']) + 10, 58)))

        x_offset = 0
        for img in im_list_upper:
            new_im.paste(img, (x_offset, 0))
            x_offset += img.size[0]

        x_offset = 0
        for img in im_list_lower:
            new_im.paste(img, (x_offset, 58))
            x_offset += img.size[0]

        new_im.save('Image/' + re.split('[./]', filename)[1] + '1.jpg')
        return new_im

    def is_px_equal(self, img1, img2, x, y):
        """
        判断两个像素是否相同
        :param img1: 图片1
        :param img2:图片2
        :param x:位置1
        :param y:位置2
        :return:像素是否相同
        """
        pix1 = img1.load()[x, y]
        pix2 = img2.load()[x, y]
        threshold = 60

        if abs(pix1[0] - pix2[0]) < threshold and abs(pix1[1] - pix2[1]) < threshold and abs(pix1[2] - pix2[2]) < threshold:
            return True
        else:
            return False

    def get_gap(self, img1, img2):
        """
        获取缺口偏移量
        :param img1: 不带缺口图片
        :param img2: 带缺口图片
        :return:
        """
        left = 60
        for i in range(left, img1.size[0]):
            for j in range(img1.size[1]):
                if not self.is_px_equal(img1, img2, i, j):
                    left = i
                    return left
        return left

    def get_track(self, distance):
        """
        根据偏移量和手动操作模拟计算移动轨迹
        :param distance: 偏移量
        :return: 移动轨迹
        """
        # 移动轨迹
        tracks = []
        # 当前位移
        current = 0
        # 减速阈值
        mid = distance * 4 / 5
        # 时间间隔
        t = 0.2
        # 初始速度
        v = 0

        while current < distance:
            if current < mid:
                a = random.uniform(2, 5)
            else:
                a = -(random.uniform(12.5, 13.5))
            v0 = v
            v = v0 + a * t
            x = v0 * t + 1 / 2 * a * t * t
            current += x

            if 0.6 < current - distance < 1:
                x = x - 0.53
                tracks.append(round(x, 2))

            elif 1 < current - distance < 1.5:
                x = x - 1.4
                tracks.append(round(x, 2))
            elif 1.5 < current - distance < 3:
                x = x - 1.8
                tracks.append(round(x, 2))

            else:
                tracks.append(round(x, 2))

        return tracks

    def get_slider(self):
        """
        获取滑块
        :return:滑块对象
        """
        try:
            slider = self.wait.until(EC.element_to_be_clickable((By.XPATH, '//div[@class="gt_slider"]/div[contains(@class,"gt_slider_knob")]')))
            return slider
        except TimeoutError:
            print('加载超时...')

    def move_to_gap(self, slider, tracks):
        """
        将滑块移动至偏移量处
        :param slider: 滑块
        :param tracks: 移动轨迹
        :return:
        """
        action = ActionChains(self.browser)
        action.click_and_hold(slider).perform()
        for x in tracks:
            action.move_by_offset(xoffset=x, yoffset=-1).perform()
            action = ActionChains(self.browser)
        time.sleep(0.6)
        action.release().perform()

    def success_check(self):
        """
        验证是否成功
        :return:
        """
        try:
            if re.findall('gt_success', self.browser.page_source, re.S):
                print('验证成功!')
                return True
            else:
                print('验证失败!')
                return False
        except TimeoutError:
            print('加载超时...')
        finally:
            time.sleep(10000)
            # self.browser.close()


if __name__ == '__main__':
    check = CrackGeetest()
    check.chrome_operate()
    bg_location_list, fullgb_location_list = check.get_geetest_image()
    img1 = check.get_merge_image('Image/fullgb.jpg', fullgb_location_list)
    img2 = check.get_merge_image('Image/bg.jpg', fullgb_location_list)
    distance = check.get_gap(img1, img2) * 1.138
    slider = check.get_slider()
    tracks = check.get_track(distance)
    print(tracks)
    check.move_to_gap(slider, tracks)
    # time.sleep(0.5)
    CHECK = check.success_check()