# coding=utf-8
import json
from datetime import datetime

from django.db.models import Sum, Q
from django.forms.models import model_to_dict

from hippo.models.bill import BillApplyRecord, BillToStatementAll, BillToAdrechange, BillToTransferBudan
from hippo.models.merchant import MerchantBillInfo, MerchantAgreement, MerchantRelevance, MerchantLicense
from hippo.models.doctor import DoctorAccount
from pay.models.statementall import StatementAll, FeeDeductionAll
from api.models.bd_transfer import BDTransferMonthToBudan
from api.models.budan import BuDan
from api.tool.datetime_tool import get_datetime
from rpc.context import get_rpc_remote_invoker
from rpc.decorators import bind_context
from rpc.tool.error_code import CODES, gen
from hippo.tool.user_tool import get_doctor_from_context
from gm_types.doctor import DOCTOR_BILLAPPLY_STATUS, DOCTOR_EXPRESS_COMPANY, DOCTOR_BILL_TYPE, \
    BILL_REFUSE_REASON, DOCTOR_BILL_CLASS, BILL_INFO_TYPE, HOSTING_TYPE
from gm_types.artemis import  ACCREDIT_TYPE
from gm_types.trade import STATEMENT_STATUS


@bind_context('doctor/finance/info', login_required=True)
def get_doctor_finance_info(ctx):
    doctor = get_doctor_from_context(ctx)
    result = {}
    if not doctor:
        gen(CODES.DOCTOR_NOT_FOUND)
    merchant = doctor.merchant
    try:
        obj = MerchantBillInfo.objects.get(merchant_id=merchant.id)
        result = model_to_dict(obj)
        # 发票抬头信息取自医生开户名称
        if result['info_type'] == BILL_INFO_TYPE.NORMAL:
            result['bill_header'] = MerchantAgreement.objects.get(merchant_id=merchant.id).first_company_name
            result['tax_id'] = MerchantAgreement.objects.get(merchant_id=merchant.id).first_company_number
        else:
            result['bill_header'] = MerchantAgreement.objects.get(merchant_id=merchant.id).first_hosting_company_name
            result['tax_id'] = MerchantAgreement.objects.get(merchant_id=merchant.id).first_hosting_company_number
    except:
        pass
    return result


@bind_context('doctor/finance/edit', login_required=True)
def edit_doctor_finance_info(ctx, finance_info):
    doctor = get_doctor_from_context(ctx)
    if not doctor:
        gen(CODES.DOCTOR_NOT_FOUND)
    merchant = doctor.merchant
    obj, _ = MerchantBillInfo.objects.get_or_create(merchant_id=merchant.id)
    for k, v in finance_info.iteritems():
        setattr(obj, k, v)
    obj.save(update_fields=finance_info.keys())
    return {'edit_record_id': obj.id}


@bind_context('doctor/bill/records', login_required=True)
def get_doctor_bill_records(ctx, start_time, stop_time, start_num=0, count=10):
    doctor = get_doctor_from_context(ctx)
    if not doctor:
        gen(CODES.DOCTOR_NOT_FOUND)
    stop_time = '{} 23:59:59'.format(stop_time)
    start_time = datetime.strptime(start_time, '%Y-%m-%d')
    stop_time = datetime.strptime(stop_time, '%Y-%m-%d %H:%M:%S')

    qs = BillApplyRecord.objects.filter(
        doctor_id=doctor.id,
        created_time__range=[start_time, stop_time]
    ).order_by('-created_time')
    data = dict()
    data['total'] = qs.count()
    records = qs[start_num: start_num + count]
    rows = []
    for r in records:
        rows.append(r.get_recordfinance_info())
    data['records'] = rows

    return data


@bind_context('doctor/bill/detail', login_required=True)
def get_doctor_bill_detail(ctx, bill_id):
    doctor = get_doctor_from_context(ctx)
    if not doctor:
        gen(CODES.DOCTOR_NOT_FOUND)
    record = BillApplyRecord.objects.get(id=bill_id)
    return record.get_finance_and_record_info()


@bind_context('doctor/bill/list', login_required=True)
def get_doctor_bill_list(ctx, start_time, stop_time, start_num=0, count=10):
    doctor = get_doctor_from_context(ctx)
    if not doctor:
        gen(CODES.DOCTOR_NOT_FOUND)
    qs = StatementAll.objects.filter(
        doctor_id=doctor.id,
        status=STATEMENT_STATUS.SETTLED,
        statement_date__gte=start_time,
        statement_date__lte=stop_time
    ).order_by('-statement_date')
    data = {}
    data['total'] = qs.count()
    periods = []
    for sa in qs[start_num: start_num + count]:
        record = {}
        record['id'] = sa.id
        record['period'] = sa.statement_date
        fda = FeeDeductionAll.objects.filter(statementall_id=sa.id)
        total_deduction = fda.aggregate(
            total_deduction=Sum('value')
        ).get('total_deduction') or 0
        st_discount = sa.service_statement.total_discount or 0
        mt_discount = sa.maidan_statement.total_discount or 0
        sa_amount = st_discount + mt_discount + total_deduction
        record['amount'] = sa_amount
        other_info = {}
        re = BillToStatementAll.objects.filter(statementall_id=sa.id).order_by('-created_time').first()
        if re:
            if re.billapplyrecord.status == DOCTOR_BILLAPPLY_STATUS.SUCCESS:
                record['status'] = 1
                record['status_desc'] = u'已申请'
                other_info['status'] = 1
                if re.billapplyrecord.express_id and re.billapplyrecord.express_company is not None:
                    other_info['info'] = u'{}，快递单号：{}'\
                        .format(DOCTOR_EXPRESS_COMPANY.getDesc(re.billapplyrecord.express_company), re.billapplyrecord.express_id)
                else:
                    other_info['info'] = u'暂无物流信息'
                record['other_info'] = other_info
            elif re.billapplyrecord.status == DOCTOR_BILLAPPLY_STATUS.PENDING:
                record['status'] = 1
                record['status_desc'] = u'已申请'
                other_info['status'] = 0
                other_info['info'] = u'已申请开票，待运营审核'
                record['other_info'] = other_info
            else:
                record['status'] = 0
                record['status_desc'] = u'可申请'
                other_info['status'] = 1
                if re.billapplyrecord.reason == BILL_REFUSE_REASON.OTHERS:
                    other_info['info'] = u'驳回理由：{}'.format(re.billapplyrecord.more_reason)
                else:
                    other_info['info'] = u'驳回理由：{}'.format(BILL_REFUSE_REASON.getDesc(re.billapplyrecord.reason))
                record['other_info'] = other_info
        else:
            record['status'] = 0
            record['status_desc'] = u'可申请'
            other_info['status'] = 0
            other_info['info'] = u''
            record['other_info'] = other_info
        periods.append(record)
    data['periods'] = periods
    return data


@bind_context('doctor/bill/rechange_list', login_required=True)
def get_rechange_bill_list(ctx, start_time, stop_time, start_num=0, count=10):
    rpc_invoker = get_rpc_remote_invoker()
    doctor = get_doctor_from_context(ctx)
    rechange_data = rpc_invoker['artemis/account/bill/rechange'](
        doctor_id = doctor.id,
        start_time=start_time,
        stop_time=stop_time,
    ).unwrap()
    assert isinstance(rechange_data['rechanges'], list)
    rechange_data['rechanges'] =  rechange_data['rechanges'][start_num: start_num+count]
    for re in rechange_data['rechanges']:
        assert isinstance(re, dict)
        other_info = dict()
        record = BillToAdrechange.objects.filter(adrechange_id=re['id']).order_by('-created_time').first()
        if record:
            if record.billapplyrecord.status == DOCTOR_BILLAPPLY_STATUS.SUCCESS:
                re['status'] = 1
                re['status_desc'] = u'已申请'
                other_info['status'] = 1
                if record.billapplyrecord.express_id and record.billapplyrecord.express_company is not None:
                    other_info['info'] = u'{}，快递单号：{}'\
                        .format(DOCTOR_EXPRESS_COMPANY.getDesc(record.billapplyrecord.express_company), record.billapplyrecord.express_id)
                else:
                    other_info['info'] = u'暂无物流信息'
                re['other_info'] = other_info
            elif record.billapplyrecord.status == DOCTOR_BILLAPPLY_STATUS.PENDING:
                re['status'] = 1
                re['status_desc'] = u'已申请'
                other_info['status'] = 0
                other_info['info'] = u'已申请开票，待运营审核'
                re['other_info'] = other_info
            else:
                re['status'] = 0
                re['status_desc'] = u'可申请'
                other_info['status'] = 1
                if record.billapplyrecord.reason == BILL_REFUSE_REASON.OTHERS:
                    other_info['info'] = u'驳回理由：{}'.format(record.billapplyrecord.more_reason)
                else:
                    other_info['info'] = u'驳回理由：{}'.format(BILL_REFUSE_REASON.getDesc(record.billapplyrecord.reason))
                re['other_info'] = other_info
        else:
            re['status'] = 0
            re['status_desc'] = u'可申请'
            other_info['status'] = 0
            other_info['info'] = u''
            re['other_info'] = other_info
    return rechange_data


@bind_context('doctor/bill/budan_list', login_required=True)
def get_budan_bill_list(ctx, start_time, stop_time, start_num=0, count=10):
    rpc_invoker = get_rpc_remote_invoker()
    doctor = get_doctor_from_context(ctx)
    bill_white = rpc_invoker['artemis/advertise/doctor/is_whitelist'](
        doctor_id=doctor.id, accredit_type=ACCREDIT_TYPE.BUDAN_BILL).unwrap()
    can_bill = bill_white['is_whitelist']
    q = Q(bdtransfermonth__doctor_id=doctor.id)
    if stop_time:
        q &= Q(budan__create_time__lte=datetime.fromtimestamp(stop_time))
    if start_time:
        q &= Q(budan__create_time__gte=datetime.fromtimestamp(start_time))
    if not can_bill:
        q &= Q(has_paid=True)
    bmtbs = BDTransferMonthToBudan.objects.filter(q).order_by('-budan__create_time')
    data = {}
    data['total'] = bmtbs.count()
    budans = []
    can_apply = True
    not_paid_budan_ids = BDTransferMonthToBudan.objects.filter(bdtransfermonth__doctor_id=doctor.id,
                                                               has_paid=False).values_list('budan_id', flat=True)
    if BillToTransferBudan.objects.filter(budan_id__in=list(not_paid_budan_ids))\
            .exclude(billapplyrecord__status=DOCTOR_BILLAPPLY_STATUS.REJECT).exists():
        can_apply = False
    for bmtb in bmtbs[start_num: start_num + count]:
        other_info = {}
        budan = {}
        budan['id'] = bmtb.budan.id
        budan['dev_projects'] = bmtb.budan.dev_projects_format
        budan['amount'] = bmtb.budan.extra_consume
        budan['should_pay'] = bmtb.budan.payment
        budan['is_finish'] = bmtb.has_paid
        budan['create_time'] = bmtb.budan.create_time.strftime('%Y-%m-%d %H:%M:%S')
        re = BillToTransferBudan.objects.filter(budan_id=bmtb.budan_id).order_by('-created_time').first()
        if re:
            if re.billapplyrecord.status == DOCTOR_BILLAPPLY_STATUS.SUCCESS:
                budan['status'] = 1
                budan['status_desc'] = u'已申请'
                other_info['status'] = 1
                if re.billapplyrecord.express_id and re.billapplyrecord.express_company is not None:
                    other_info['info'] = u'{}，快递单号：{}'\
                        .format(DOCTOR_EXPRESS_COMPANY.getDesc(re.billapplyrecord.express_company), re.billapplyrecord.express_id)
                else:
                    other_info['info'] = u'暂无物流信息'
                budan['other_info'] = other_info
            elif re.billapplyrecord.status == DOCTOR_BILLAPPLY_STATUS.PENDING:
                budan['status'] = 1
                budan['status_desc'] = u'已申请'
                other_info['status'] = 0
                other_info['info'] = u'已申请开票，待运营审核'
                budan['other_info'] = other_info
            else:
                budan['status'] = 0
                budan['status_desc'] = u'可申请'
                other_info['status'] = 1
                if re.billapplyrecord.reason == BILL_REFUSE_REASON.OTHERS:
                    other_info['info'] = u'驳回理由：{}'.format(re.billapplyrecord.more_reason)
                else:
                    other_info['info'] = u'驳回理由：{}'.format(BILL_REFUSE_REASON.getDesc(re.billapplyrecord.reason))
                budan['other_info'] = other_info
        else:
            budan['status'] = 0
            budan['status_desc'] = u'可申请'
            other_info['status'] = 0
            other_info['info'] = u''
            budan['other_info'] = other_info
        budans.append(budan)
    data['can_apply'] = can_apply
    data['budans'] = budans
    return data


@bind_context('doctor/bill/apply', login_required=True)
def doctor_bill_apply(ctx, periods, bill_type, category, is_online):
    doctor = get_doctor_from_context(ctx)
    if not doctor:
        gen(CODES.DOCTOR_NOT_FOUND)
    merchant = doctor.merchant
    try:
        ma = MerchantAgreement.objects.get(merchant_id=merchant.id)
    except:
        gen(CODES.NO_BILL_INFO)
    if category == DOCTOR_BILL_CLASS.COMMISSION:
        is_apply = False
        for pid in periods:
            is_apply = BillToStatementAll.objects.filter(
                statementall_id=pid, billapplyrecord__status__in=[DOCTOR_BILLAPPLY_STATUS.PENDING,
                                                                  DOCTOR_BILLAPPLY_STATUS.SUCCESS]
            ).exists()
            if is_apply:
                break
        if is_apply:
            gen(CODES.HAS_APPLY_BILL)
        statements = StatementAll.objects.filter(id__in=periods)
        amount = 0
        for sa in statements:
            fda = FeeDeductionAll.objects.filter(statementall_id=sa.id)
            total_deduction = fda.aggregate(
                total_deduction=Sum('value')
            ).get('total_deduction') or 0
            st_discount = sa.service_statement.total_discount or 0
            mt_discount = sa.maidan_statement.total_discount or 0
            sa_amount = st_discount + mt_discount + total_deduction
            amount += sa_amount

        # 获取当前提交快照信息
        obj = MerchantBillInfo.objects.get(merchant_id=merchant.id)
        finance_info = model_to_dict(obj)
        if finance_info['info_type'] == BILL_INFO_TYPE.NORMAL:
            finance_info['bill_header'] = MerchantAgreement.objects.get(merchant_id=merchant.id).first_company_name
            finance_info['tax_id'] = MerchantAgreement.objects.get(merchant_id=merchant.id).first_company_number
        else:
            finance_info['bill_header'] = MerchantAgreement.objects.get(merchant_id=merchant.id).first_hosting_company_name
            finance_info['tax_id'] = MerchantAgreement.objects.get(merchant_id=merchant.id).first_hosting_company_number
        result = {}
        result['finance_info'] = finance_info
        result['statement_ids'] = periods
        billapplyrecord = BillApplyRecord.objects.create(
            amount=amount,
            bill_type=bill_type,
            doctor_id=doctor.id,
            status=DOCTOR_BILLAPPLY_STATUS.PENDING,
            snapshot=json.dumps(result),
            is_online=is_online
        )
        for pid in periods:
            BillToStatementAll.objects.create(
                billapplyrecord=billapplyrecord,
                statementall_id=pid
            )
    elif category ==  DOCTOR_BILL_CLASS.RECHANGE:
        is_apply = False
        for pid in periods:
            is_apply = BillToAdrechange.objects.filter(
                adrechange_id=pid, billapplyrecord__status__in=[DOCTOR_BILLAPPLY_STATUS.PENDING,
                                                                DOCTOR_BILLAPPLY_STATUS.SUCCESS]
            ).exists()
            if is_apply:
                break
        if is_apply:
            gen(CODES.HAS_APPLY_BILL)
        rpc_invoker = get_rpc_remote_invoker()
        count_data = rpc_invoker['artemis/account/bill/count'](ids=periods).unwrap()
        obj = MerchantBillInfo.objects.get(merchant_id=merchant.id)
        finance_info = model_to_dict(obj)
        if finance_info['info_type'] == BILL_INFO_TYPE.NORMAL:
            finance_info['bill_header'] = MerchantAgreement.objects.get(merchant_id=merchant.id).first_company_name
            finance_info['tax_id'] = MerchantAgreement.objects.get(merchant_id=merchant.id).first_company_number
        else:
            finance_info['bill_header'] = MerchantAgreement.objects.get(merchant_id=merchant.id).first_hosting_company_name
            finance_info['tax_id'] = MerchantAgreement.objects.get(merchant_id=merchant.id).first_hosting_company_number
        result = {}
        result['finance_info'] = finance_info
        result['rechange_ids'] = periods
        billapplyrecord = BillApplyRecord.objects.create(
            amount=count_data['amount__sum'],
            bill_type=bill_type,
            doctor_id=doctor.id,
            status=DOCTOR_BILLAPPLY_STATUS.PENDING,
            snapshot=json.dumps(result),
            category=DOCTOR_BILL_CLASS.RECHANGE,
            is_online=is_online
        )
        for pid in periods:
            BillToAdrechange.objects.create(
                billapplyrecord=billapplyrecord,
                adrechange_id=pid
            )
    elif category == DOCTOR_BILL_CLASS.BUDAN:
        is_apply = False
        for pid in periods:
            is_apply = BillToTransferBudan.objects.filter(
                budan_id=pid, billapplyrecord__status__in=[DOCTOR_BILLAPPLY_STATUS.PENDING,
                                                                  DOCTOR_BILLAPPLY_STATUS.SUCCESS]
            ).exists()
            if is_apply:
                break
        if is_apply:
            gen(CODES.HAS_APPLY_BILL)
        budans = BuDan.objects.filter(id__in=periods)
        amount = 0
        for budan in budans:
            amount += budan.payment

        # 获取当前提交快照信息
        obj = MerchantBillInfo.objects.get(merchant_id=merchant.id)
        finance_info = model_to_dict(obj)
        if finance_info['info_type'] == BILL_INFO_TYPE.NORMAL:
            finance_info['bill_header'] = MerchantAgreement.objects.get(merchant_id=merchant.id).first_company_name
            finance_info['tax_id'] = MerchantAgreement.objects.get(merchant_id=merchant.id).first_company_number
        else:
            finance_info['bill_header'] = MerchantAgreement.objects.get(merchant_id=merchant.id).first_hosting_company_name
            finance_info['tax_id'] = MerchantAgreement.objects.get(merchant_id=merchant.id).first_hosting_company_number
        result = {}
        result['finance_info'] = finance_info
        result['statement_ids'] = periods
        billapplyrecord = BillApplyRecord.objects.create(
            amount=amount,
            bill_type=bill_type,
            doctor_id=doctor.id,
            status=DOCTOR_BILLAPPLY_STATUS.PENDING,
            snapshot=json.dumps(result),
            category=DOCTOR_BILL_CLASS.BUDAN,
            is_online=is_online
        )
        for pid in periods:
            BillToTransferBudan.objects.create(
                billapplyrecord=billapplyrecord,
                budan_id=pid
            )
    else:
        pass


@bind_context('doctor/bill/info_type', login_required=True)
def doctor_bill_apply(ctx):
    doctor = get_doctor_from_context(ctx)
    if not doctor:
        gen(CODES.DOCTOR_NOT_FOUND)
    merchant = doctor.merchant
    info = list()
    try:
        ma = MerchantAgreement.objects.get(merchant_id=merchant.id)
        default_choice = {
            'info_type': BILL_INFO_TYPE.NORMAL,
            'bill_header': ma.first_company_name,
            'tax_id': ma.first_company_number,
        }
        info.append(default_choice)
    except:
        pass
    try:
        ma = MerchantAgreement.objects.get(merchant_id=merchant.id)
        if ma.hosting_type == HOSTING_TYPE.COMPANY:
            handle_choice = {
                'info_type': BILL_INFO_TYPE.HANDLER,
                'bill_header': ma.first_hosting_company_name,
                'tax_id': ma.first_hosting_company_number,
            }
            info.append(handle_choice)
    except:
        pass
    return {'info': info}
