# -*- coding: UTF-8 -*-
from __future__ import absolute_import

import json
import time

from django.db import IntegrityError
from django.db.models import Q
from gm_types.gaia import COUPON_TYPES

from hera.queries.statementall import StatementAllDQ, StatementAllOperationDQ
from hippo.models import Doctor
from pay.models.statementall import StatementAll, StatementAllOperation, FeeDeductionAll
from rpc.tool.dict_mixin import to_dict
from rpc.decorators import bind_context
from rpc.exceptions import (RPCIntegrityError, RPCNotFoundException)
from rpc.tool.log_tool import info_logger
from pay.models.statement import Statement, FeeDeduction, OrderStatementRelationship, StatementAccount
from ..datatables import StatementOrderDT
from ..queries.statement import StatementDQ, StatementOperationDQ
from api.models import Order
from ..queries.statementorderfeed import StatementOrderDQ
from api.tasks.export_excel_task import export_not_settle_statement
from gm_types.trade import STATEMENT_STATUS, STATEMENT_OPERATION_TYPE, OPERATION_ROLE
from api.tasks.statement_all_task import export_all_unchecked_excel_task
from api.models.area import Province, City

uri_pre = 'hera/statement'
STATUS_CAN_MODIFY = [STATEMENT_STATUS.CHECKED, STATEMENT_STATUS.APPLIED, STATEMENT_STATUS.AUDITED,
                     STATEMENT_STATUS.CREATED, STATEMENT_STATUS.DEFEAT, STATEMENT_STATUS.REFUSED,
                     STATEMENT_STATUS.VOID]


@bind_context(uri_pre + '/query')
def statement_datatable(ctx, options):
    from api.tool.user_tool import get_user_from_context
    user = get_user_from_context(ctx)
    dtobj = StatementDQ(init_q=Q(statement_date__lt=201711))
    return dtobj.process(**options)


@bind_context(uri_pre + '/listupdate')
def statement_listupdate(ctx, items):
    info = []
    for obj in items:
        statementinfo = Statement.objects.get(id=obj['id'])
        statementinfo.in_user_name = obj['in_user_name']
        statementinfo.in_topic_content = obj['in_topic_content']
        statementinfo.in_topic_reply = obj['in_topic_reply']
        statementinfo.in_topic_chat = obj['in_topic_chat']
        statementinfo.is_filter = obj['is_filter']
        statementinfo.save()
        info.append(obj['id'])
    return info


@bind_context(uri_pre + '/get')
def statement_detail(ctx, statement_id, options=None):
    try:
        statement = Statement.objects.get(id=statement_id)
    except:
        raise RPCNotFoundException
    if options is None:
        options = {
            'fields': None,
            'excludes': None,
            'expands': None,
        }
    statement_data = to_dict(statement, **options)
    statement_data['feededuction_sum'] = statement.feededuction_sum
    statement_data['settle_price'] = statement.settle_price
    statement_data['sub_data'] = json.loads(statement.sub_data or '{}')

    statement_data['refused_records'] = []
    for item in statement.refused_records.order_by('-create_time').values('create_time', 'reason'):
        item['create_time'] = str(item['create_time'])
        statement_data['refused_records'].append(item)
    return statement_data


@bind_context(uri_pre + '/edit')
def statement_edit(ctx, statement_id=None, statement_info=None):
    if statement_info is None:
        return None

    if statement_id is None:
        try:
            statement = Statement.objects.create(**statement_info)
        except IntegrityError:
            raise RPCIntegrityError
    else:
        try:
            statement = Statement.objects.get(id=statement_id)
        except:
            info_logger.info(__import__('traceback').format_exc())
            raise RPCNotFoundException
        for k, v in statement_info.iteritems():
            setattr(statement, k, v)
        statement.save()

    return statement.id


@bind_context(uri_pre + '/order_query')
def statement_orders_query(ctx, options):
    dtobj = StatementOrderDQ()
    return dtobj.process(**options)


@bind_context(uri_pre + '/order_list')
def statement_orders(ctx, req_data, statement_id):
    dtobj = StatementOrderDT(Order, init_q=Q(statement__id=statement_id))
    return dtobj.process(req_data)


@bind_context(uri_pre + '/feededuction_list')
def statement_orders(ctx, statement_id):
    try:
        statement = Statement.objects.get(id=statement_id)
    except:
        raise RPCNotFoundException
    return {
        'gt_feedeductions': [to_dict(obj) for obj in statement.fee_deduction.filter(value__gt=0)],
        'lt_feedeductions': [to_dict(obj) for obj in statement.fee_deduction.filter(value__lt=0)],
    }


@bind_context(uri_pre + '/feededuction_get')
def feededuction_detail(ctx, feededuction_id, options=None):
    try:
        feededuction = FeeDeduction.objects.get(id=feededuction_id)
    except:
        raise RPCNotFoundException
    if options is None:
        options = {
            'fields': None,
            'excludes': None,
            'expands': None,
        }
    feededuction_data = to_dict(feededuction, **options)
    return feededuction_data


@bind_context(uri_pre + '/feededuction_edit')
def feededuction_edit(ctx, statement_id, arr=None):
    try:
        statement = Statement.objects.get(id=statement_id)
    except:
        raise RPCNotFoundException
    feededuction_ids = []
    for feededuction_info in arr:
        id = feededuction_info.get('id', None)
        feededuction_info.pop('id')
        if not feededuction_info.get('value'):
            continue
        if id:
            feededuction = FeeDeduction.objects.get(id=id)
            for k, v in feededuction_info.iteritems():
                setattr(feededuction, k, v)
            feededuction.save()
        else:
            feededuction = FeeDeduction.objects.create(statement=statement, **feededuction_info)
        feededuction_ids.append(feededuction.id)
    print(statement.fee_deduction.exclude(id__in=feededuction_ids))
    statement.fee_deduction.exclude(id__in=feededuction_ids).delete()


@bind_context(uri_pre + '/operation_query')
def statementoperation_datatable(ctx, options):
    dtobj = StatementOperationDQ()
    return dtobj.process(**options)


@bind_context(uri_pre + '/settle_detail')
def settle_detail(ctx, order_id):
    order = Order.objects.get(id=order_id)
    settle_data = order.settle_data()
    coupon_info = {x['coupon_type']: x for x in order.get_order_coupon_infos()}
    platform_coupon = coupon_info.get(COUPON_TYPES.PLATFORM, {})
    settle_data.update(platform_coupon)
    return settle_data


@bind_context(uri_pre + '/export_not_settle')
def export_not_settle(ctx):
    user = ctx.session.user
    ids = list(
        Statement.history_objects.filter(status__in=[STATEMENT_STATUS.CHECKED, STATEMENT_STATUS.DEFEAT]).values_list('id',
                                                                                                             flat=True))
    export_not_settle_statement.delay(user.email)
    return ids


# 总对账单相关
@bind_context(uri_pre + '/query_all')
def statement_all_datatable(ctx, options):
    from api.tool.user_tool import get_user_from_context
    user = get_user_from_context(ctx)
    dtobj = StatementAllDQ()
    return dtobj.process(**options)


@bind_context(uri_pre + '/all_get')
def statement_all_get(ctx, statement_all_id):
    """
    返回总对账单详情页
    :param ctx:
    :param statement_all_id:
    :return: 结算总金额，结算单状态，申述列表
    """
    statement_all = StatementAll.objects.get(id=statement_all_id)
    refuse_list = StatementAllOperation.objects.filter(
        statementall_id=statement_all.id,
        optype=STATEMENT_OPERATION_TYPE.REFUSE
    ).order_by('-id')
    return {
        'amount': statement_all.total_settle_amount,
        'status': statement_all.status,
        'refuse_list': [{
                            'reason': item.content,
                            'time': item.operate_at.strftime("%Y-%m-%d %H:%M:%S")
                        } for item in refuse_list]
    }


@bind_context(uri_pre + '/service_statement_info')
def service_statement_info(ctx, statement_all_id):
    """
    总对账单中美购对账单的信息
    :param ctx:
    :param statement_all_id:
    :return:美购结算金额，普通美购结算金额，分销美购结算金额，pos机汇款金额， 美购订单list
    """
    statement_all = StatementAll.objects.get(id=statement_all_id)
    result = {
        'new_total_settle_amount': statement_all.service_statement.new_total_settle_amount,
        'normal_service_amount': statement_all.service_statement.normal_service_amount,
        'fenxiao_service_amount': statement_all.service_statement.fenxiao_service_amount,
        'pos_back': statement_all.service_statement.pos_back,
    }
    orders = OrderStatementRelationship.objects.filter(
        statement=statement_all.service_statement).order_by('-order__created_time')

    order_list = [item.order_info for item in orders]

    result['order_list'] = order_list
    """
    订单总价、预付款、抽成佣金、商家承担美券金额等汇总
    """
    total_num_amount=pre_payment_price_amount=discount_amount=merchant_deduction_amount=0
    for item in order_list:
        total_num_amount += item.get('total_num', 0)
        pre_payment_price_amount += item.get('pre_payment_price', 0)
        discount_amount += item.get('discount', 0)
        merchant_deduction_amount += item.get('merchant_deduction', 0)
    result.update(total_num_amount=total_num_amount, pre_payment_price_amount=pre_payment_price_amount, discount_amount=discount_amount, merchant_deduction_amount=merchant_deduction_amount)
    return result


@bind_context(uri_pre + '/maidan_statement_info')
def maidan_statement_info(ctx, statement_all_id):
    """
    总对账单中买单对账单的信息
    :param ctx:
    :param statement_all_id:
    :return:买单结算金额，医生折后价，买单订单list
    """
    statement_all = StatementAll.objects.get(id=statement_all_id)
    result = {
        'settle_amount': statement_all.maidan_statement.settle_amount_cent / 100,
        'original_amount': statement_all.maidan_statement.original_amount_cent / 100,
    }

    order_list = [{
                      'id': item.id,
                      'doctor_name': item.doctor.name,
                      'maidan_name': item.maidan_name,
                      'maidan_price': item.maidan_price_cent / 100,
                      'payment': item.payment_cent / 100,
                      'discount': item.discount_cent / 100,
                      'settle_price': item.discount_cent / 100,
                      'created_time': item.created_time.strftime("%Y-%m-%d %H:%M:%S")
                  } for item in statement_all.maidan_statement.orders.all().
                      order_by('-maidanorderstatementrelationship__order__created_time')]

    result['order_list'] = order_list
    """
    买单金额、实际支付金额、抽成金额汇总
    """
    discount_amount=maidan_prince_amount=payment_amount=0
    for item in order_list:
        maidan_prince_amount += item.get('maidan_price', 0)
        payment_amount += item.get('payment', 0)
        discount_amount += item.get('discount', 0)
    result.update(maidan_prince_amount=maidan_prince_amount, payment_amount=payment_amount, discount_amount=discount_amount)
    return result


@bind_context(uri_pre + '/feededuction_info')
def feededuction_info(ctx, statement_all_id):
    """

    :param ctx:
    :param statement_all_id:
    :return:
    """
    statement_all = StatementAll.objects.get(id=statement_all_id)
    return {
        'feededuction_sum': statement_all.feededuction_sum
    }


@bind_context(uri_pre + '/operation_query_all')
def operation_query_all(ctx, options):
    from api.tool.user_tool import get_user_from_context
    user = get_user_from_context(ctx)
    dtobj = StatementAllOperationDQ()
    return dtobj.process(**options)


@bind_context(uri_pre + '/export_all_unchecked_excel')
def export_all_unchecked_excel(ctx):
    """
    导出未结算对账单
    :param ctx:
    :return:
    """
    user = ctx.session.user
    export_all_unchecked_excel_task.delay(user.email)


@bind_context(uri_pre + '/feededuction_all_list')
def statement_orders(ctx, statement_all_id):
    try:
        statementall = StatementAll.objects.get(id=statement_all_id)
    except:
        raise RPCNotFoundException
    return {
        'gt_feedeductions': [to_dict(obj) for obj in statementall.fee_deduction.filter(value__gt=0)],
        'lt_feedeductions': [to_dict(obj) for obj in statementall.fee_deduction.filter(value__lt=0)],
    }


@bind_context(uri_pre + '/feededuction_all_edit')
def feededuction_all_edit(ctx, statement_all_id, arr=None):
    try:
        statementall = StatementAll.objects.get(id=statement_all_id)
    except:
        raise RPCNotFoundException
    feededuction_ids = []
    for feededuction_info in arr:
        id = feededuction_info.get('id', None)
        if not feededuction_info.get('value'):
            continue
        info = {
            'comment': feededuction_info['comment'],
            'value': feededuction_info['value']
        }
        if id:
            feededuction = FeeDeductionAll.objects.get(id=id)
            for k, v in info.iteritems():
                setattr(feededuction, k, v)
            feededuction.save()
        else:
            feededuction = FeeDeductionAll.objects.create(statementall=statementall, **info)
        feededuction_ids.append(feededuction.id)
    print(statementall.fee_deduction.exclude(id__in=feededuction_ids))
    statementall.fee_deduction.exclude(id__in=feededuction_ids).delete()


@bind_context(uri_pre + '/import_excel')
def import_excel(ctx, data):

    result = []
    error_result = []
    for index, obj in enumerate(data):
        try:
            statement = Statement.objects.get(id=obj[0], status__in=STATUS_CAN_MODIFY)
            province = Province.objects.get(name=obj[1])
            city = City.objects.get(name=obj[2])
            bank = obj[3]
            subbranch = obj[4]
            account_name = obj[5]
            account_number = obj[6]
            sa, _ = StatementAccount.objects.get_or_create(statement_id=statement.id)
            sa.province = province
            sa.city = city
            sa.bank = bank
            sa.subbranch = subbranch
            sa.account_number = account_number
            sa.account_name = account_name
            sa.save()
            result.append(statement.id)
        except:
            error_result.append(index)
            continue

    return result, error_result

@bind_context(uri_pre + '/all_get_excel')
def statement_all_get_excel(ctx, data):
    """
    对比excel和数据库的数据
    :param ctx:
    :param data: excel表格中的数据
    :return:
    """
    flag = 1
    for i in data:
        statement_all = StatementAll.objects.filter(id=i[0]).first()
        error_mes = ''
        if statement_all:
            if statement_all.statement_date != i[2]:
                error_mes += u'该对账单结算周期不匹配 '
            if statement_all.total_settle_amount != i[3]:
                error_mes += u'该对账单结算总金额不匹配 '
            if STATEMENT_STATUS.getDesc(statement_all.status) != i[4] or \
                    STATEMENT_STATUS.getDesc(statement_all.status) not in [u'待结算', u'财务打款失败']:
                error_mes += u'该对账单当前结算状态错误 '
            if i[5] not in [u'已结算', u'财务打款失败']:
                error_mes += u'该对账单当前待修改状态错误 '
        else:
            error_mes += u'对账单ID不存在 '
        if not error_mes:
            i.append(u'正确')
        else:
            flag = 0
            i.append(error_mes)
    return data, flag

@bind_context(uri_pre + '/import_excel_v2')
def import_excel_v2(ctx, data):

    result = []
    error_result = []
    user = ctx.session.user
    for index, obj in enumerate(data):
        try:
            statement = StatementAll.objects.get(id=obj[0], status__in=[STATEMENT_STATUS.CHECKED, STATEMENT_STATUS.DEFEAT])
            if obj[5] == u'已结算':
                statement_status = 4
                statementalloperation_status = STATEMENT_OPERATION_TYPE.SETTLE
            if obj[5] == u'财务打款失败':
                statement_status = 6
                statementalloperation_status = STATEMENT_OPERATION_TYPE.BANK_DEFEAT

            statement.status = statement_status
            statement.settle_time = time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))
            statement.save()
            StatementAllOperation.objects.create(statementall_id=obj[0], operator_id=user.person.id,
                                                                    optype=statementalloperation_status,
                                                                    role=OPERATION_ROLE.STAFF)

            result.append(statement.id)
        except:
            error_result.append(index)
            continue

    return result, error_result
