#pylint: disable=logging-format-interpolation,too-many-locals,too-many-branches
import logging
import traceback
from django.core.management import CommandParser
from jutil.xml import xml_to_dict
from jbank.models import Payout, PayoutStatus, PAYOUT_ERROR, PAYOUT_WAITING_UPLOAD, PAYOUT_UPLOADED, WsEdiConnection
from jbank.wsedi import wsedi_upload_file, wsedi_execute
from jutil.command import SafeCommand


logger = logging.getLogger(__name__)


class Command(SafeCommand):
    help = """
        Upload Finnish bank files
        """

    def add_arguments(self, parser: CommandParser):
        parser.add_argument('--payout', type=int)
        parser.add_argument('--file-type', type=str, help='E.g. XL, NDCORPAYS, pain.001.001.03')
        parser.add_argument('--verbose', action='store_true')
        parser.add_argument('--force', action='store_true')
        parser.add_argument('--default-ws', type=int)
        parser.add_argument('--ws', type=int)

    def do(self, *args, **options):
        default_ws = WsEdiConnection.objects.get(id=options['default_ws']) if options['default_ws'] else None
        assert default_ws is None or isinstance(default_ws, WsEdiConnection)
        file_type = options['file_type']
        if not file_type:
            print('--file-type required (e.g. XL, NDCORPAYS, pain.001.001.03)')
            return

        payouts = Payout.objects.all()
        if options['payout']:
            payouts = Payout.objects.filter(id=options['payout'])
        else:
            payouts = payouts.filter(state=PAYOUT_WAITING_UPLOAD)
            if options['ws']:
                payouts = payouts.filter(connection_id=options['ws'])

        for p in list(payouts):
            assert isinstance(p, Payout)
            p.refresh_from_db()
            ws_connection = p.connection or default_ws

            if p.state != PAYOUT_WAITING_UPLOAD:
                logger.info('Skipping {} since not in state PAYOUT_WAITING_UPLOAD'.format(p))
                continue
            if ws_connection and not ws_connection.enabled:
                logger.info('WS connection %s not enabled, skipping payment %s', ws_connection, p)
                continue

            response_code = ''
            response_text = ''
            try:
                # upload file
                logger.info('Uploading payment id={} {} file {}'.format(p.id, file_type, p.full_path))
                with open(p.full_path, 'rt') as fp:
                    file_content = fp.read()
                p.state = PAYOUT_UPLOADED
                p.save(update_fields=['state'])
                if ws_connection:
                    content = wsedi_execute(ws_connection, 'UploadFile', file_content=file_content, file_type=file_type, verbose=options['verbose'])
                    data = xml_to_dict(content, array_tags=['FileDescriptor'])
                else:
                    res = wsedi_upload_file(file_content=file_content, file_type=file_type, file_name=p.file_name, verbose=options['verbose'])
                    logger.info('HTTP response {}'.format(res.status_code))
                    logger.info(res.text)
                    data = res.json()

                # parse response
                response_code = data.get('ResponseCode', '')[:4]
                response_text = data.get('ResponseText', '')[:255]
                if response_code != '00':
                    msg = 'WS-EDI file {} upload failed: {} ({})'.format(p.file_name, response_text, response_code)
                    logger.error(msg)
                    raise Exception('Response code {} ({})'.format(response_code, response_text))
                if 'FileDescriptors' in data:
                    fds = data.get("FileDescriptors", {}).get("FileDescriptor", [])
                    fd = {} if not fds else fds[0]
                    file_reference = fd.get('FileReference', '')
                    if file_reference:
                        p.file_reference = file_reference
                        p.save(update_fields=['file_reference'])
                PayoutStatus.objects.create(payout=p, msg_id=p.msg_id, file_name=p.file_name, response_code=response_code,
                                            response_text=response_text, status_reason='File upload OK')

            except Exception as e:
                long_err = "File upload failed ({}): ".format(p.file_name) + traceback.format_exc()
                logger.error(long_err)
                short_err = 'File upload failed: ' + str(e)
                p.state = PAYOUT_ERROR
                p.save(update_fields=['state'])
                PayoutStatus.objects.create(payout=p, msg_id=p.msg_id, file_name=p.file_name, response_code=response_code,
                                            response_text=response_text, status_reason=short_err[:255])
