import os
import re
import textwrap

from PIL import Image, ImageDraw, ImageFont

ENGLISH_WORDS = re.compile(r'^[a-zA-Z0-9\.\-\s]+$')
WHITE = (255, 255, 255)
BLACK = (30, 30, 30)
SEMI_BLACK = (200, 200, 200)
TRANSPARENT_BLACK = (0, 0, 0, 68)


class Cover(object):
    WIDTH = 600
    HEIGHT = 858
    TOP_HEIGHT = 480

    STYLE_TOP = 8
    STYLE_FULL = 9

    COPYRIGHT_TEXT = 'GENERATED BY DOOCER'

    def __init__(self, config):
        self.config = config
        self.cover = Image.new('RGB', (self.WIDTH, self.HEIGHT), WHITE)
        self.draw = ImageDraw.Draw(self.cover)
        self.style = 0

    def draw_background(self, cover_file):
        img = Image.open(cover_file, 'r')
        w, h = img.size
        if w >= self.WIDTH and h >= self.HEIGHT:
            return self._draw_full_background(img)

        if w >= self.WIDTH:
            img.thumbnail((w, h))
            return self._draw_top_background(img)

        return False

    def draw_top_text(self, suffix):
        text = self.COPYRIGHT_TEXT + ' / ' + suffix
        font_file = self.config['EBOOK_ENG_REGULAR_FONT']
        font = truetype(font_file, 20)
        self.draw.text((32, 20), text, WHITE, font)

    def draw_title_text(self, title):
        title = title.upper()
        count = len(title)
        if count < 10:
            wrap = 6
        elif count < 20:
            wrap = 10
        elif count < 30:
            wrap = 12
        else:
            wrap = 15
        if self.style == self.STYLE_TOP:
            return self._draw_half_title(title, count, wrap)
        return self._draw_full_title(title, count, wrap)

    def draw_bottom_text(self, text):
        if self.style == self.STYLE_FULL:
            return self._draw_full_bottom_text(text)
        if self.style == self.STYLE_TOP:
            return self._draw_top_bottom_text(text)

    def draw_issue_count(self, number):
        text = str(number)
        font_file = self.config['EBOOK_ENG_BOLD_FONT']
        font = truetype(font_file, 80)
        w, _ = self.draw.textsize(text, font=font)
        self.draw.text((self.WIDTH - 48 - w, 36), text, WHITE, font)

    def save(self, output):
        folder = os.path.dirname(output)
        if not os.path.isdir(folder):
            os.makedirs(folder)
        self.cover.save(output)
        return output

    def _draw_top_background(self, img):
        w, h = img.size
        scale = min(w / self.WIDTH, h / self.TOP_HEIGHT)
        w = int(w / scale)
        h = int(h / scale)
        img.thumbnail((w, h))

        w, h = img.size
        self.style = self.STYLE_TOP
        box = (int((self.WIDTH - w) / 2), 0)
        self.cover.paste(img, box)
        mask = Image.new('RGBA', (self.WIDTH, h), TRANSPARENT_BLACK)
        self.cover.paste(mask, (0, 0), mask=mask)
        return True

    def _draw_full_background(self, img):
        w, h = img.size
        scale = min(w / self.WIDTH, h / self.HEIGHT)
        w = int(w / scale)
        h = int(h / scale)
        img.thumbnail((w, h))

        self.style = self.STYLE_FULL
        w, h = img.size
        box = (int((self.WIDTH - w) / 2), int((self.HEIGHT - h) / 2))
        self.cover.paste(img, box)
        mask = Image.new('RGBA', (self.WIDTH, self.HEIGHT), TRANSPARENT_BLACK)
        self.cover.paste(mask, (0, 0), mask=mask)
        return True

    def _get_bold_font(self, text, font_size):
        eng_bold_font = self.config['EBOOK_ENG_BOLD_FONT']
        cjk_bold_font = self.config['EBOOK_CJK_BOLD_FONT']
        if ENGLISH_WORDS.search(text):
            font_file = eng_bold_font
            font_size = int(font_size * 1.8)
        else:
            font_file = cjk_bold_font
        return truetype(font_file, font_size)

    def _draw_half_title(self, title, count, wrap):
        lines = textwrap.wrap(title, wrap)
        font_size = int(360 / min(wrap, count))
        font = self._get_bold_font(title, font_size)

        y = self.TOP_HEIGHT + 48
        for line in lines:
            w, h = self.draw.textsize(line, font=font)
            x = int((self.WIDTH - w) / 2)
            self.draw.text((x, y), line, BLACK, font)
            y = y + h

    def _draw_full_title(self, title, count, wrap):
        lines = textwrap.wrap(title, wrap)
        font_size = int(480 / min(wrap, count))
        font = self._get_bold_font(title, font_size)
        y = int(self.HEIGHT * 0.2)
        for line in lines:
            w, h = self.draw.textsize(line, font=font)
            self.draw.text((36, y), line, WHITE, font)
            y = y + h
        return True

    def _get_regular_font(self, text, base_width):
        font_size = int(base_width / len(text))
        if ENGLISH_WORDS.search(text):
            font_file = self.config['EBOOK_ENG_REGULAR_FONT']
            font_size = int(font_size * 2)
        else:
            font_file = self.config['EBOOK_CJK_REGULAR_FONT']
        return truetype(font_file, font_size)

    def _draw_top_bottom_text(self, text):
        y = self.HEIGHT - 110
        x = int(self.WIDTH / 2 - 40)
        rect = [x, y, x + 80, y + 4]
        self.draw.rectangle(rect, fill=SEMI_BLACK)
        font = self._get_regular_font(text, 80)

        w, _ = self.draw.textsize(text, font=font)
        x = int((self.WIDTH - w) / 2)
        self.draw.text((x, y + 20), text, SEMI_BLACK, font)

    def _draw_full_bottom_text(self, text):
        x = 48
        y = int(self.HEIGHT * 0.78)
        rect = [x, y, x + 108, y + 10]
        self.draw.rectangle(rect, fill=WHITE)
        font = self._get_regular_font(text, 120)
        self.draw.text((x, y + 32), text, WHITE, font)
        return True


def truetype(font_file, font_size):
    if isinstance(font_file, tuple):
        return ImageFont.truetype(font_file[0], font_size, font_file[1])
    return ImageFont.truetype(font_file, font_size)
