# coding=utf-8
# create by oldman at 2017/10/31
from __future__ import unicode_literals, absolute_import

import datetime
from abc import ABCMeta
from abc import abstractmethod

from django.db import transaction
from django.conf import settings
from gm_types.trade import STATEMENT_STATUS
from gm_types.trade import STATEMENT_OPERATION_TYPE
from gm_types.trade import OPERATION_ROLE

from pay.models.statementall import StatementAllAccount, StatementAllOperation, StatementAll
from rpc.tool.error_code import gen, CODES
from message.views.push import doctor_noti_doctor_ids

TIME_ZONE = settings.TIME_ZONE

__all__ = ['StatementOp', 'CreateOp', 'ApplyOp', 'AuditOp', 'CheckOp', 'RefuseOp', 'SettleOp',
           'BankDefaultOp', 'NameDefaultOp', 'FinResetOp']


class StatementAllOp(object):
    __metaclass__ = ABCMeta

    optype = 0
    role = 0
    operator = None
    pre_status_list = None

    def __init__(self, statementall, operator=None, role=None):
        self.statementall = statementall
        if operator:
            self.operator = operator

        if role:
            self.role = role
        self.condition_assert()

    def pre_status_assert(self):
        if self.pre_status_list and self.statementall.status not in self.pre_status_list:
            raise gen(CODES.STATEMENT_STATUS_ERROR)

    def condition_assert(self):
        self.pre_status_assert()

    @abstractmethod
    def operate(self, *args, **kwargs):
        return

    def update_account(self):
        doctor_account = self.statementall.doctor.merchant.account
        doctor_account_info = {
            'statementall': self.statementall,
            'province_id': doctor_account.province_id or None,
            'city_id': doctor_account.city_id or None,
            'bank': doctor_account.bank,
            'account_name': doctor_account.account_name,
            'account_number': doctor_account.account_number,
            'account_type': doctor_account.account_type,
            'subbranch': doctor_account.subbranch,
        }
        if getattr(self.statementall, 'account', None):
            doctor_account_info.pop('statementall')
            account = self.statementall.account
            for k, v in doctor_account_info.iteritems():
                setattr(account, k, v)
            account.save()
        else:
            StatementAllAccount.objects.create(**doctor_account_info)

    def record(self):
        StatementAllOperation.objects.create(
            statementall=self.statementall,
            operator=self.operator,
            optype=self.optype,
            role=self.role,
        )

    def do(self, *args, **kwargs):
        self.condition_assert()
        with transaction.atomic():
            self.operate(*args, **kwargs)
            self.statementall.save()
            self.record()


class CreateOp(StatementAllOp):
    optype = STATEMENT_OPERATION_TYPE.CREATE
    role = OPERATION_ROLE.SYSTEM

    pre_status_list = None

    def operate(self):
        self.statementall.status = STATEMENT_STATUS.APPLIED
        self.statementall.poundage_rate = getattr(settings, 'SELF_SUPPORT_POUNDAGE_RATE', 0)


# 医生不再需要发起, 无用
class ApplyOp(StatementAllOp):
    # 医生发起结算申请
    optype = STATEMENT_OPERATION_TYPE.APPLY
    role = OPERATION_ROLE.DOCTOR
    # 刚创建, 对运营的审核不满意
    pre_status_list = (STATEMENT_STATUS.CREATED, STATEMENT_STATUS.AUDITED)

    def operate(self):
        self.statementall.status = STATEMENT_STATUS.APPLIED


class AuditOp(StatementAllOp):
    # 运营审核完成修改金额
    optype = STATEMENT_OPERATION_TYPE.AUDIT
    role = OPERATION_ROLE.STAFF
    pre_status_list = (
        STATEMENT_STATUS.VOID, STATEMENT_STATUS.APPLIED, STATEMENT_STATUS.REFUSED, STATEMENT_STATUS.CREATED)
    message = u'{}医生您好！您{}年{}月的对账单已经审核完成，请尽快确认本月结算金额，' \
              u'在电脑上登录医生后台即可查看。如有问题，请联系您的商务。'

    def operate(self):
        self.statementall.status = STATEMENT_STATUS.AUDITED
        self.statementall.settle_amount = self.statementall.total_settle_amount
        message = self.message.format(self.statementall.doctor.name, self.statementall.statement_date / 100,
                                      str(self.statementall.statement_date)[4:])
        doctor_noti_doctor_ids(doctor_ids=[self.statementall.doctor.id], alert=message)


class CheckOp(StatementAllOp):
    optype = STATEMENT_OPERATION_TYPE.CHECK
    role = OPERATION_ROLE.DOCTOR
    pre_status_list = (STATEMENT_STATUS.AUDITED,)

    def operate(self):
        # 之前的对账单都处于待结算及以上状态
        is_exists = StatementAll.objects.filter(doctor=self.statementall.doctor, status=STATEMENT_STATUS.AUDITED,
                                                statement_date__lt=self.statementall.statement_date).exists()
        if is_exists:
            raise gen(CODES.SETTLEMENT_HAVE_NOT_CONFIRM)
        self.statementall.status = STATEMENT_STATUS.CHECKED
        self.statementall.merchant_confirm_time = datetime.datetime.now()
        self.update_account()
        self.statementall.check_snapshot = self.statementall.get_snapshot()


class RefuseOp(StatementAllOp):
    optype = STATEMENT_OPERATION_TYPE.REFUSE
    role = OPERATION_ROLE.DOCTOR
    pre_status_list = (STATEMENT_STATUS.AUDITED,)

    def record(self):
        StatementAllOperation.objects.create(
            statementall=self.statementall,
            operator=self.operator,
            optype=self.optype,
            role=self.role,
            content=self.reason,
        )

    def operate(self, reason):
        self.statementall.status = STATEMENT_STATUS.REFUSED
        # 因为operate在record之前...
        self.reason = reason


class SettleOp(StatementAllOp):
    optype = STATEMENT_OPERATION_TYPE.SETTLE
    role = OPERATION_ROLE.STAFF
    pre_status_list = (STATEMENT_STATUS.CHECKED, STATEMENT_STATUS.DEFEAT)
    message = '{}医生您好！您{}年{}月的结算金额已经打款到账，请到您的对应账户查看。如有问题，请联系您的商务。'

    def operate(self):
        self.update_account()
        self.statementall.status = STATEMENT_STATUS.SETTLED
        self.statementall.settle_time = datetime.datetime.now()
        self.statementall.settle_snapshot = self.statementall.get_snapshot()
        self.statementall.service_statement.settle_snapshot = self.statementall.service_statement.get_snapshot()
        for order in self.statementall.service_statement.orders.all():
            order.is_settled = True
            order.save()
        message = self.message.format(self.statementall.doctor.name, self.statementall.statement_date / 100,
                                      str(self.statementall.statement_date)[4:])
        doctor_noti_doctor_ids(doctor_ids=[self.statementall.doctor.id], alert=message)


class BankDefaultOp(StatementAllOp):
    optype = STATEMENT_OPERATION_TYPE.BANK_DEFEAT
    role = OPERATION_ROLE.STAFF
    pre_status_list = (STATEMENT_STATUS.CHECKED, STATEMENT_STATUS.DEFEAT,)

    def operate(self):
        self.update_account()
        self.statementall.status = STATEMENT_STATUS.DEFEAT


class NameDefaultOp(StatementAllOp):
    optype = STATEMENT_OPERATION_TYPE.NAME_DEFEAT
    role = OPERATION_ROLE.STAFF
    pre_status_list = (STATEMENT_STATUS.CHECKED, STATEMENT_STATUS.DEFEAT,)

    def operate(self):
        self.update_account()
        self.statementall.status = STATEMENT_STATUS.DEFEAT


class FinResetOp(StatementAllOp):
    optype = STATEMENT_OPERATION_TYPE.FIN_RESET
    role = OPERATION_ROLE.STAFF
    pre_status_list = (STATEMENT_STATUS.SETTLED, STATEMENT_STATUS.DEFEAT,)

    def operate(self):
        self.statementall.status = STATEMENT_STATUS.CHECKED
