# coding=utf-8
from __future__ import absolute_import, print_function, unicode_literals

import json
import logging
import urlparse
import datetime

import requests
from django.conf import settings
from django.utils import timezone
from gm_types.gaia import ORDER_STATUS
from requests.exceptions import RequestException

from api.business.tag import TagControl
from api.models import Service
from api.models.tickets import Punishment

from .es import tzlc
from .transfer import get_area_tag_info, MAX_TIME
from rpc.cache import data_transfer_cache
from talos.abstractviews.diary import get_service_diary_count
from hippo.tool.merchant_tool import doctor_merchant_map
from search.utils.area import get_nearby_city_tag
from agile.services.tag import (TagMapOldTagService, get_tag_v3_first_demands_by_tag_v3_ids,
                                get_tag_v3_first_solutions_by_tag_v3_ids, get_tag_v3_names_by_tag_v3_ids,
                                get_tag_v3_positions_by_tag_v3_ids, get_tag_v3_second_demands_by_tag_v3_ids,
                                get_tag_v3_second_solutions_by_tag_v3_ids,get_tagv3_analysis_info,get_tagv3_ids_by_tagv3_names,
                                get_tag_v3_first_positions_by_tag_v3_ids,
                                get_tag_v3_first_positions_by_tag_v3_ids,
                                get_first_demand_ids_by_name,get_second_demand_ids_by_name,get_first_position_ids_by_name,get_second_position_ids_by_name,
                                get_first_solution_ids_by_name,get_second_solution_ids_by_name)

MARS_API_HOST = settings.DATA_TRANSFER_MARS_API_HOST
MARS_AUTH_KEY = settings.DATA_TRANSFER_MARS_AUTH_KEY

ORDER_BOUGHT_STATUS = [
    ORDER_STATUS.PAID,
    ORDER_STATUS.USED,
    ORDER_STATUS.REFUNDED,
    ORDER_STATUS.SETTLED,
    ORDER_STATUS.WAIT_REFUNDED,
]


class MarsDataError(Exception):
    def __init__(self, api=None, http_status=None, error_code=None, message=''):
        self.api = api
        self.http_status = http_status
        self.error_code = error_code
        self.message = message

    def __str__(self):
        return 'api[%s] http_status[%s] error_code[%s] message[%s]' % (
            self.api, self.http_status, self.error_code, self.message)


def _get_cache(cache_key):
    cache_res = data_transfer_cache.get(cache_key)
    if cache_res is not None:
        return json.loads(cache_res)
    else:
        return None


def _set_cache(cache_key, value, expire=86400):
    """cached in one day
    """
    value = json.dumps(value)
    return data_transfer_cache.setex(cache_key, expire, value)


def _get_cur_date():
    now = tzlc(timezone.now())
    if now.hour >= 12:  # 超过12点取昨天
        return now - datetime.timedelta(days=1)
    else:
        return now - datetime.timedelta(days=2)


def mars_call(method, params, from_cache=False):
    raise MarsDataError()
    if from_cache:
        # read from cache
        cache_key_params = '#'.join([
            k + ':' + str(v) for k, v in sorted(params.items())
        ])
        cache_key = method + '#' + cache_key_params
        cache_res = _get_cache(cache_key)
        if cache_res is not None:
            return cache_res

    payload = params.copy()
    payload['gmauth_key'] = MARS_AUTH_KEY
    url = urlparse.urlunparse(('http', MARS_API_HOST, method, '', '', ''))

    try:
        resp = requests.post(url, data=payload, allow_redirects=False)
        if resp.status_code != 200:
            raise MarsDataError(api=url, http_status=resp.status_code)
        res = resp.json()
        if res['error'] != 0:
            raise MarsDataError(api=url, http_status=200, error_code=res['error'])
        res = res['data']
    except RequestException as e:
        raise MarsDataError(
            api=url,
            http_status=None,
            error_code=None,
            message='request exception: %s' % e)

    if from_cache:
        # set cache
        _set_cache(cache_key, res)
    return res


def get_smart_rank_new(s):
    try:
        smart_rnk = s.smartrank.new_smart_rank
    except Service.smartrank.RelatedObjectDoesNotExist:
        smart_rnk = 0.0
    return smart_rnk


def get_hospital_info(hospital):
    def hospital_type2(hospital):
        try:
            # check if type is oversea
            b = hospital.city.province.country_id != 'china'
            b = b or hospital.city.province_id in ('aomen', 'xianggang', 'taiwan')
            if b:
                return '9'
            else:
                return hospital.hospital_type

        except:
            return hospital.hospital_type

    h = {
        'id': hospital.id,
        'name': hospital.name,
        'hospital_type': hospital.hospital_type,
        'city_count': hospital.city_count,
        'chain_count': hospital.chain_count,
        'area_count': hospital.area_count,
        'hospital_type2': hospital_type2(hospital),
        'is_high_quality': hospital.is_high_quality,
    }
    if hospital.city:
        h['city_name'] = hospital.city.name
        h['city_province_name'] = hospital.city.province.name
        h.update(get_area_tag_info(hospital.city))
    if hospital.officer:
        h['officer_name'] = hospital.officer.name
    return h


def get_doctor_info(doctor):
    d = {
        'id': doctor.id,
        'name': doctor.name,
        'title': doctor.title,
        'famous_doctor': doctor.big,
    }
    if doctor.hospital_id:
        d['hospital'] = get_hospital_info(doctor.hospital)
    return d


def get_service_info(service):
    s = service
    res = {}
    keys = [
        'short_description', 'detail_description', 'channel', 'ordering', 'rating', 'is_sink',
        'share_get_cashback', 'tip',
    ]
    for k in keys:
        res[k] = getattr(s, k)
    res.update({
        'service_id': s.id,
        'service_name': s.name,
        'is_stage': s.is_stage,
        'is_insurance': s.is_support_insurance,
        'is_fenqi': s.is_support_renmai_no_pay,
        'gift_rank': s.get_gift_rank_for_es(),
    })
    res['is_can_be_sold'] = s.is_can_be_sold_for_es()
    res['start_time'] = tzlc(s.start_time)
    res['end_time'] = tzlc(s.end_time) if s.end_time else MAX_TIME
    # closure tags
    closure_tags = TagControl.get_ancestors(
        initial_set=s.tags.filter(is_online=True),
        exclude_init=False,
        is_online_only=True)
    res['closure_tag_ids'] = [t.id for t in closure_tags]
    res['closure_tags'] = [t.name for t in closure_tags]

    res['smart_rank2'] = get_smart_rank_new(s)
    res['is_online'] = s.is_online
    if s.doctor and (not s.doctor.is_online):
        res['is_online'] = False

    # 美购医生的商户医生id
    res['merchant_doctor_id'] = doctor_merchant_map([s.doctor_id])[s.doctor_id]
    # 销量使用假数据
    res['sales_count'] = s.get_dajiadouzaimai_rank_for_es()
    # case count
    service_diary_count = get_service_diary_count([s.id])
    res['case_count'] = service_diary_count[0]['diary_count']
    # pv
    try:
        date_str = _get_cur_date()
        date_str = date_str.strftime('%Y-%m-%d')
        res['pv'] = mars_call('/api/service/pv',
                              params={'record_time': date_str, 'service_id': s.id}, from_cache=True)['pv_cnt']
    except MarsDataError as e:
        logger = logging.getLogger('mars_call')
        logger.warning('Mars call error for service_id[%s]: %s' % (s.id, e))
        res['pv'] = 0
    # sink
    if s.tickets_result:
        res['ticket_sink_start_time'] = tzlc(s.tickets_result.start_sink)
        res['ticket_sink_end_time'] = tzlc(s.tickets_result.end_sink)
    # 机构罚单下沉
    punishment = Punishment.get_punishment_by_doctor_id(s.doctor.id).get('service', None)
    if punishment and punishment.get('type', None) in ['limit', ]:
        res['org_sink_start_time'] = tzlc(punishment['start_time'])
        res['org_sink_end_time'] = tzlc(punishment['end_time'])

    # 新标签v3相关字段
    (need_refresh_data,second_demands_set,second_solutions_set,second_positions_set,first_demands_set,first_solutions_set,
     first_positions_set,project_tags_set,first_classify_ids_set,second_classify_ids_set,first_classify_names_set,
     second_classify_names_set)=get_tagv3_analysis_info(content_id=s.id,content_type="service")
    if need_refresh_data:
        tagv3_ids = list()
        if len(project_tags_set)>0:
            tagv3_ids = get_tagv3_ids_by_tagv3_names(names_list=list(project_tags_set))
            first_demands_set = first_demands_set.union(set(get_tag_v3_first_demands_by_tag_v3_ids(tagv3_ids)))
            first_solutions_set = first_solutions_set.union(set(get_tag_v3_first_solutions_by_tag_v3_ids(tagv3_ids)))
            first_positions_set = first_positions_set.union(set(get_tag_v3_first_positions_by_tag_v3_ids(tagv3_ids)))
            second_demands_set = second_demands_set.union(set(get_tag_v3_second_demands_by_tag_v3_ids(tagv3_ids)))
            second_solutions_set = second_solutions_set.union(set(get_tag_v3_second_solutions_by_tag_v3_ids(tagv3_ids)))
            second_positions_set = second_positions_set.union(set(get_tag_v3_positions_by_tag_v3_ids(tagv3_ids)))

        res["tags_v3"] = list(project_tags_set)
        res["first_demands"] = list(first_demands_set)
        res["second_demands"] = list(second_demands_set)
        res["first_solutions"] = list(first_solutions_set)
        res["second_solutions"] = list(second_solutions_set)
        res["positions"] = list(first_positions_set)
        res["second_positions"] = list(second_positions_set)

        res["tagv3_ids"] = tagv3_ids
        res["first_demands_ids"] = get_first_demand_ids_by_name(list(first_demands_set))
        res["second_demands_ids"] = get_second_demand_ids_by_name(list(second_demands_set))
        res["first_solutions_ids"] = get_first_solution_ids_by_name(list(first_solutions_set))
        res["second_solutions_ids"] = get_second_solution_ids_by_name(list(second_solutions_set))
        res["first_positions_ids"] = get_first_position_ids_by_name(list(first_positions_set))
        res["second_positions_ids"] = get_second_position_ids_by_name(list(second_positions_set))

        res["first_classify_ids"] = list(first_classify_ids_set)
        res["first_classify_names"] = list(first_classify_names_set)
        res["second_classify_ids"] = list(second_classify_ids_set)
        res["second_classify_names"] = list(second_classify_names_set)

    return res


def get_sku(instance):
    sku = instance
    s = sku.service

    if sku.is_delete or not s.check_is_valid_for_es():
        return {
            'id': sku.id,
            'service_id': s.id,
            'is_online': False,
        }

    res = {
        'id': sku.id,
        'name': u'+'.join(sku.items_name)
    }
    res.update(get_service_info(s))  # 美购属性
    res['doctor'] = get_doctor_info(s.doctor)

    # price
    prices_info = s.get_sku_price_range_for_es(sku)
    res['price_range'] = [{
        'start_time': tzlc(p['start_time']),
        'end_time': tzlc(p['end_time']),
        'price': p['price'],
    } for p in prices_info]

    # special
    specialitems = sku.get_special_info_for_es()
    res['special'] = [{
        'id': special_id,
        'item_id': special_info['item_id'],
        'sku_id': special_info['sku_id'],
        'position': special_info['position'],
        'has_pos': special_info['has_pos'],
    } for special_id, special_info in specialitems.items()]

    # add nearby city tags
    res['nearby_city_tags'] = []
    if s.doctor and s.doctor.hospital and s.doctor.hospital.city:
        cts = get_nearby_city_tag(s.doctor.hospital.city_id)
        res['nearby_city_tags'] = cts
    return res
