#!/usr/bin/env python
# -*- coding:utf-8 -*-
#
#   Author  :   RobertDing
#   E-mail  :   robertdingx@gmail.com
#   Date    :   18/01/29 17:21:58
#   Desc    :   提取新氧数据
#

import re
import json

import requests

from django.core.management import BaseCommand

from gm_types.wiki import ACHE_LEVEL_NEW, Enum, PRODUCT_TYPE
from gm_types.wiki import PRODUCT_IMAGE_TYPE, PRODUCT_PARAMS, DIRECTORY_TYPE
from gm_types.wiki import ITEM_H1, DRUG_H1, MACHINE_H1, MATERIAL_H1
from gm_types.wiki import TREATMENT_TYPE

from gm_upload import IMG_TYPE, upload

from wiki.models.item import Item, ItemAfterKnow
from wiki.models.brand import Brand
from wiki.models.product import Product
from wiki.models.product import ProductImage, ProductParams, ProductAttestation
from wiki.models.collect import Collect, CollectItem
from wiki.models.directory import Directory


class ANESTHESIA_TYPE(Enum):
    NONE = ('0', u'无需麻醉')
    NONE_SURFACE = ('1', u'无需麻醉或表麻')
    SURFACE = ('2', u'表麻')
    PART = ('3', u'局麻')
    PART1 = ('3', u'局部麻醉')
    SURFACE_PART = ('4', u'局麻/全麻')
    SURFACE_PART1 = ('4', u'局部麻醉/全麻')
    PART_SLEEP = ('5', u'局麻/睡眠麻醉')
    PART_SLEEP1 = ('5', u'局部麻醉/睡眠麻醉')
    ALL = ('6', u'全麻')
    ALL_SLEEP = ('7', u'全麻/睡眠')


class Command(BaseCommand):
    def handle(self, *args, **options):
        ImportItem().handle()
        ImportProduct().handle()
        ImportCollect().handle()
        ReplaceImage().handle()
        pass


class ReplaceImage(object):
    def handle(self):
        for x in Brand.objects.all():
            print(u'brand url{}'.format(x.name))
            x.image_url = self.replace(x.image_url)
            x.save(update_fields=['image_url'])
        for x in ProductImage.objects.all().select_related('product'):
            print(u'image url{}'.format(x.product.name))
            x.image_url = self.replace(x.image_url)
            x.save(update_fields=['image_url'])
        for x in ProductAttestation.objects.all().select_related('product'):
            print(u'attestation url{}'.format(x.product.name))
            x.attestation_image = self.replace(x.attestation_image)
            x.save(update_fields=['attestation_image'])

    def replace(self, url):
        if not url:
            return ''
        return upload(requests.get(url).content, img_type=IMG_TYPE.NOWATERMARK)


class Open(object):
    def open(self, filename):
        return '[{}]'.format(open(filename).read().strip()).replace('}\n', '},')


class ImportCollect(Open):
    sy_item_file_name = 'sy_item.json'
    sy_drug_file_name = 'sy_drug.json'
    sy_instrument_file_name = 'sy_apparatus.json'
    sy_material_file_name = 'sy_material.json'

    def handle(self):
        CollectItem.objects.all().delete()
        Collect.objects.all().delete()
        Directory.objects.all().delete()
        self.create_item()
        self.create_drug()
        self.create_instrument()
        self.create_material()

    def create_instrument(self):
        menus = json.loads(self.open(self.sy_instrument_file_name))
        self.create_one(menus, DIRECTORY_TYPE.MACHINE, MACHINE_H1)

    def create_drug(self):
        menus = json.loads(self.open(self.sy_drug_file_name))
        self.create_one(menus, DIRECTORY_TYPE.DRUG, DRUG_H1)

    def create_material(self):
        menus = json.loads(self.open(self.sy_material_file_name))
        self.create_one(menus, DIRECTORY_TYPE.MATERIAL, MATERIAL_H1)

    def create_one(self, menus, directory_type, h1):
        h1_map = {v: k for k, v in h1.choices}
        for menu in menus:
            for i, c in enumerate(menu['item_list']):
                brand = None
                product = None
                pid = c['son_item_product_id']
                if c['type'] == '2':
                    assert directory_type == DIRECTORY_TYPE.DRUG
                    brand = Brand.objects.get(soyoung_id=pid)
                elif c['type'] == '1':
                    product = Product.objects.get(soyoung_id=pid)
                else:
                    raise Exception
                Directory.objects.get_or_create(
                    dirctory_type=directory_type,
                    model_type=h1_map[menu['name']],
                    brand=brand,
                    product=product,
                    defaults={'rank': i*100}
                )

    def create_item(self):
        menus = json.loads(open(self.sy_item_file_name).read())
        h1_map = {v: k for k, v in ITEM_H1.choices}
        for menu in menus:
            for i, c in enumerate(menu['menu2_list']):
                collect, created = Collect.objects.get_or_create(
                    name=c['name'], description=c['intro']
                )
                if not created:
                    continue
                Directory.objects.create(
                    dirctory_type=DIRECTORY_TYPE.ITEM,
                    model_type=h1_map[menu['name']],
                    collect=collect,
                    rank=i*100
                )
                for j, d in enumerate(c['list']):
                    item = Item.objects.get(soyoung_id=d['item_id'])
                    CollectItem.objects.get_or_create(
                        collect=collect,
                        item=item,
                        defaults={'rank': j*100}
                    )
            pass
        pass


class ImportProduct(Open):
    sy_drug_file_name = 'sy_drug_html.json'
    sy_instrument_file_name = 'sy_apparatus_html.json'
    sy_material_file_name = 'sy_material_html.json'

    def handle(self):
        Brand.objects.all().delete()
        ProductParams.objects.all().delete()
        ProductImage.objects.all().delete()
        Product.objects.all().delete()
        self.create_drug()
        self.create_instrument()
        self.create_material()
        self.create_relation()

    def create_relation(self):
        for item in Item.objects.all():
            print(u'similar' + item.name)
            item.similar_item = Item.objects.filter(soyoung_id__in=json.loads(item.similar_sy_item))
            item.related_product = Product.objects.filter(soyoung_id__in=json.loads(item.related_sy_drug))
        for product in Product.objects.all():
            print(u'similar' + product.name)
            product.similar_product = Product.objects.filter(soyoung_id__in=json.loads(product.similar_sy_product))

    def create_instrument(self):
        instruments = json.loads(self.open(self.sy_instrument_file_name))
        extra = {'product_type': PRODUCT_TYPE.INSTRUMENT}
        for instrument in instruments:
            assert instrument['type'] == 2
            self.create_one(instrument, extra)

    def create_drug(self):
        drugs = json.loads(self.open(self.sy_drug_file_name))
        extra = {'brand': None, 'product_type': PRODUCT_TYPE.DRUG}
        for drug in drugs:
            if drug.get('type') == 3:
                self.create_one(drug, extra)
            else:
                self.create_brand(drug)

    def create_material(self):
        materials = json.loads(self.open(self.sy_material_file_name))
        extra = {'product_type': PRODUCT_TYPE.MATERIALS}
        for material in materials:
            assert material['type'] == 1
            self.create_one(material, extra)

    def create_one(self, one, extra):
        if Product.objects.filter(soyoung_id=one['id'], product_type=extra['product_type']).exists():
            return
        print(one['name'])
        if one.get('brand_info', {}).get('id'):
            brand_info = one['brand_info']
            brand_info['drug_intro'] = {
                'pic': brand_info['pic'],
                'list': brand_info['intro_list'],
            }
            brand_info['principle'] = {}
            extra['brand'] = self.create_brand(brand_info)
        intro = one['intro']
        merit_map = {x['title']: x['content'] for x in one['merit']}
        intro_map = {x['title']: x['content'] for x in intro['intro_list']}
        operation_map = {x['title']: x['desc'] for x in one['operation_file']}
        anesthesia_map = {v: k for k, v in ANESTHESIA_TYPE.choices}
        treatment_method_map = {v: k for k, v in TREATMENT_TYPE.choices}
        p = re.compile(u'品牌.+产地 ?：(.+?)(?:临床.+年)?(?:上市时间.+)?公司/厂商.+')
        p_name = PRODUCT_TYPE.getDesc(extra['product_type'])
        data = {
            'soyoung_id': one['id'],
            'name': one['name'],
            'theory': one['principle'].get('content', '').strip(),
            'after_know': one['reaction'],
            'safe_tips': one['notice'],

            'advantage': merit_map.get(u'优点：', ''),
            'disadvantage': merit_map.get(u'缺点：', ''),

            'description': intro_map[p_name + u'简介'],
            'special': intro_map[p_name + u'特色'],
            'other_name': intro_map.get(p_name + u'别名', ''),
            'effect': ','.join(intro_map.get(u'功效', [])),
            'application_range': intro_map.get(u'适用范围', ''),
            'similar_sy_product': json.dumps(intro_map.get(u'相似' + p_name, [])),
            'price': intro_map.get(u'参考价格', ''),
            'origin': (p.findall(intro_map.get(p_name + u'档案')) or [''])[0],

            'treatment_method': treatment_method_map[operation_map.get(u'操作方式')],
            'anesthesia_method': anesthesia_map[operation_map.get(u'麻醉方式')],
            'treatment_doctor': operation_map.get(u'操作人员资质', ''),
            'treatment_num': operation_map.get(u'治疗周期', ''),
            'treatment_time': operation_map.get(u'操作时长', ''),
            'recover_time': operation_map.get(u'恢复时间', ''),
            'maintain_time': operation_map.get(u'效果持续', ''),
        }
        data.update(extra)
        product = Product.objects.create(**data)
        self.create_params(product, one['drug_param'])
        self.create_images(product, one.get('distinguish', []), intro.get('pic', ''))
        self.create_auth(product, one['auth'])

    def create_brand(self, brand):
        exist_brand = Brand.objects.filter(soyoung_id=brand['id']).first()
        if exist_brand:
            return exist_brand
        p = re.compile(u'所属公司: (.+)上市时间: (.+)')
        intro = brand['drug_intro']
        data = {
            'soyoung_id': brand['id'],
            'name': brand['name'],
            'image_url': intro['pic'],
            'theory': brand['principle'].get('content', '').strip(),
            'description': '',
            'company': '',
            'market_time': '',
        }
        for x in intro['list']:
            title = x['title']
            if title == u'品牌简介':
                data['description'] = x['content']
            elif title == u'品牌档案':
                company, market_time = p.findall(x['content'])[0]
                data['company'] = company
                data['market_time'] = market_time

        brand_obj = Brand.objects.create(**data)
        extra = {'brand': brand_obj, 'product_type': PRODUCT_TYPE.DRUG}
        for drug in brand.get('product_list', []):
            assert drug['type'] == 3
            self.create_one(drug, extra)
        return brand_obj

    def create_params(self, drug, params):
        params_map = {x['title']: x['content'] for x in params}
        type_map = {v: k for k, v in PRODUCT_PARAMS.choices}
        for key, value in params_map.items():
            ProductParams.objects.create(
                product=drug,
                params_type=type_map[key],
                params_message=value
            )

    def create_images(self, drug, distinguishes, pic):
        ProductImage.objects.create(
            product=drug,
            image_url=pic or '',
            image_type=PRODUCT_IMAGE_TYPE.PRODUCT
        )
        for x in distinguishes:
            ProductImage.objects.create(
                product=drug,
                image_type=PRODUCT_IMAGE_TYPE.VERRIFY,
                image_url=x['pic'],
                info=x['content']
            )

    def create_auth(self, product, auth):
        p = re.compile(u'(?:<li>.*?(?:alt="(\w+).*?").*?(?:lazy-src="(\S+?)").*?</li>)')
        for type, pic in p.findall(auth):
            ProductAttestation.objects.create(
                product=product,
                attestation_type=type,
                attestation_image=pic
            )

class ImportItem(Open):
    sy_item_file_name = 'sy_item_html.json'

    def handle(self):
        Item.objects.all().delete()
        ItemAfterKnow.objects.all().delete()
        items = json.loads(open(self.sy_item_file_name).read())
        for item in items:
            print(item['name'])
            if Item.objects.filter(soyoung_id=item['id']).exists():
                continue
            data = {
                'soyoung_id': item['id'],
                'name': item['name'],
                'related_sy_drug': json.dumps(item['drug']),
                'pre_know': item['surgery_before'],
            }
            data.update(self.intro_data(item))
            data.update((self.crowd_data(item)))
            data.update(self.operation_data(item))
            item_obj = Item.objects.create(**data)
            self.create_after_know(item_obj, item['surgery_after'])

    def intro_data(self, item):
        intro_map = {
            u'项目简介': 'description',
            u'项目特色': 'effect',
            u'项目别名': 'other_name',
            u'功效': 'use_result',
            u'相似项目': 'similar_sy_item',
            u'参考价格': 'price',
            # '适用人群特征': 'fit_people',
        }
        result = {}
        for intro in item['intro']:
            title = intro['title']
            content = intro['content']
            if title not in intro_map:
                continue
            if title == u'功效':
                content = ','.join(content)
            elif title == u'相似项目':
                content = json.dumps(content)
            result[intro_map[title]] = content
        return result

    def crowd_data(self, item):
        crowd_map = {
            u'适合人群': 'fit_people',
            u'禁忌人群': 'avoid_people',
            u'优点': 'advantage',
            u'缺点': 'disadvantage',
        }
        return {
            crowd_map[x['title']]: x['content']
            for x in item['crowd'] if x['title'] in crowd_map
        }

    def operation_data(self, item):
        operation_map = {
            u'治疗时长': 'treatment_time',
            u'麻醉方式': 'anesthesia_method',
            u'恢复时间': 'recover_time',
            u'治疗周期': 'treatment_num',
            u'操作人员资质': 'treatment_doctor',
            u'操作方式': 'treatment_method',
            u'疼痛感': 'ache_level',
            u'效果持续': 'maintain_time',
        }
        result = {}
        anesthesia_map = {v: k for k, v in ANESTHESIA_TYPE.choices}
        treatment_method_map = {v: k for k, v in TREATMENT_TYPE.choices}
        for operation in item['operation_file']:
            if operation['title'] not in operation_map:
                continue
            title = operation_map[operation['title']]
            desc = operation['desc']
            if title == 'anesthesia_method':
                desc = anesthesia_map[desc]
            if title == 'treatment_method':
                desc = treatment_method_map[desc]
            elif title == 'ache_level':
                desc = {
                    u'无痛': ACHE_LEVEL_NEW.ZERO,
                    u'轻度疼痛': ACHE_LEVEL_NEW.ONE,
                    u'中度疼痛': ACHE_LEVEL_NEW.TWO,
                    u'剧烈疼痛': ACHE_LEVEL_NEW.FIVE,
                }[desc]
            result[title] = desc
        return result

    def create_after_know(self, item, surgery_after):
        p = re.compile(u'恢复提示：(.+)护理方法：(.*)')
        for i, data in enumerate(surgery_after):
            desc = data['desc']
            if u'护理方法：' in desc:
                tip, care = p.findall(desc)[0]
            elif desc.startswith(u'恢复提示：'):
                tip = desc[5:]
                care = ''
            else:
                raise Exception
            ItemAfterKnow.objects.create(
                item=item,
                rank=i*100,
                title=data['title'],
                recover_tips=tip,
                care_method=care
            )
