#! /usr/bin/env python3
# -*- coding: utf-8 -*-

import re
import math
import json
import gettext
import traceback
from decimal import *
from ikabot.helpers.process import set_child_mode
from ikabot.helpers.varios import addThousandSeparator
from ikabot.helpers.gui import enter, banner
from ikabot.helpers.getJson import getCity
from ikabot.helpers.signals import setInfoSignal
from ikabot.helpers.planRoutes import waitForArrival
from ikabot.helpers.pedirInfo import getIdsOfCities, read
from ikabot.config import *
from ikabot.helpers.botComm import *
from ikabot.helpers.resources import *
from ikabot.helpers.market import *


t = gettext.translation('buyResources', localedir, languages=languages, fallback=True)
_ = t.gettext


def chooseResource(session, city):
    """
    Parameters
    ----------
    session : ikabot.web.session.Session
    city : dict
    """
    print(_('Which resource do you want to buy?'))
    for index, material_name in enumerate(materials_names):
        print('({:d}) {}'.format(index+1, material_name))
    choise = read(min=1, max=5)
    resource = choise - 1
    if resource == 0:
        resource = 'resource'
    data = {
        'cityId': city['id'],
        'position': city['pos'],
        'view': 'branchOffice',
        'activeTab': 'bargain',
        'type': 444,
        'searchResource': resource,
        'range': city['rango'],
        'backgroundView': 'city',
        'currentCityId': city['id'],
        'templateView': 'branchOffice',
        'currentTab': 'bargain',
        'actionRequest': actionRequest,
        'ajax': 1
    }
    # this will set the chosen resource in the store
    session.post(payloadPost=data)
    resource = choise - 1
    # return the chosen resource
    return resource


def getOffers(session, city):
    """
    Parameters
    ----------
    session : ikabot.web.session.Session
    city : dict
    Returns
    -------
    offers : list[dict]
    """
    html = getMarketHtml(session, city)
    hits = re.findall(r'short_text80">(.*?) *<br/>\((.*?)\)\s *</td>\s *<td>(\d+)</td>\s *<td>(.*?)/td>\s *<td><img src="skin/resources/icon_(\w+)\.png[\s\S]*?white-space:nowrap;">(\d+)\s[\s\S]*?href="\?view=takeOffer&destinationCityId=(\d+)&oldView=branchOffice&activeTab=bargain&cityId=(\d+)&position=(\d+)&type=(\d+)&resource=(\w+)"', html)
    offers = []
    for hit in hits:
        offer = {
            'ciudadDestino': hit[0],
            'jugadorAComprar': hit[1],
            'bienesXminuto': int(hit[2]),
            'amountAvailable': int(hit[3].replace(',', '').replace('.', '').replace('<', '')),
            'tipo': hit[4],
            'precio': int(hit[5]),
            'destinationCityId': hit[6],
            'cityId': hit[7],
            'position': hit[8],
            'type': hit[9],
            'resource': hit[10]
        }
        offers.append(offer)
    return offers


def calculateCost(offers, total_amount_to_buy):
    """
    Parameters
    ----------
    offers : list[dict]
    total_amount_to_buy : int
    Returns
    -------
    total_cost : int
    """
    total_cost = 0
    for offer in offers:
        if total_amount_to_buy == 0:
            break
        buy_amount = min(offer['amountAvailable'], total_amount_to_buy)
        total_amount_to_buy -= buy_amount
        total_cost += buy_amount * offer['precio']
    return total_cost


def chooseCommertialCity(commercial_cities):
    """
    Parameters
    ----------
    commercial_cities : list[dict]

    Returns
    -------
    commercial_city : dict
    """
    print(_('From which city do you want to buy resources?\n'))
    for i, city in enumerate(commercial_cities):
        print('({:d}) {}'.format(i + 1, city['name']))
    selected_city_index = read(min=1, max=len(commercial_cities))
    return commercial_cities[selected_city_index - 1]


def buyResources(session, event, stdin_fd, predetermined_input):
    """
    Parameters
    ----------
    session : ikabot.web.session.Session
    event : multiprocessing.Event
    stdin_fd: int
    predetermined_input : multiprocessing.managers.SyncManager.list
    """
    sys.stdin = os.fdopen(stdin_fd)
    config.predetermined_input = predetermined_input
    try:
        banner()

        # get all the cities with a store
        commercial_cities = getCommercialCities(session)
        if len(commercial_cities) == 0:
            print(_('There is no store build'))
            enter()
            event.set()
            return

        # choose which city to buy from
        if len(commercial_cities) == 1:
            city = commercial_cities[0]
        else:
            city = chooseCommertialCity(commercial_cities)
            banner()

        # choose resource to buy
        resource = chooseResource(session, city)
        banner()

        # get all the offers of the chosen resource from the chosen city
        offers = getOffers(session, city)
        if len(offers) == 0:
            print(_('There are no offers available.'))
            enter()
            event.set()
            return

        # display offers to the user
        total_price = 0
        total_amount = 0
        for offer in offers:
            amount = offer['amountAvailable']
            price = offer['precio']
            cost = amount * price
            print(_('amount:{}').format(addThousandSeparator(amount)))
            print(_('price :{:d}').format(price))
            print(_('cost  :{}').format(addThousandSeparator(cost)))
            print('')
            total_price += cost
            total_amount += amount

        # ask how much to buy
        print(_('Total amount available to purchase: {}, for {}').format(addThousandSeparator(total_amount), addThousandSeparator(total_price)))
        available = city['freeSpaceForResources'][resource]
        if available < total_amount:
            print(_('You just can buy {} due to storing capacity').format(addThousandSeparator(available)))
            total_amount = available
        print('')
        amount_to_buy = read(msg=_('How much do you want to buy?: '), min=0, max=total_amount)
        if amount_to_buy == 0:
            event.set()
            return

        # calculate the total cost
        (gold, __) = getGold(session, city)
        total_cost = calculateCost(offers, amount_to_buy)

        print(_('\nCurrent gold: {}.\nTotal cost  : {}.\nFinal gold  : {}.'). format(addThousandSeparator(gold), addThousandSeparator(total_cost), addThousandSeparator(gold - total_cost)))
        print(_('Proceed? [Y/n]'))
        rta = read(values=['y', 'Y', 'n', 'N', ''])
        if rta.lower() == 'n':
            event.set()
            return

        print(_('It will be purchased {}').format(addThousandSeparator(amount_to_buy)))
        enter()
    except KeyboardInterrupt:
        event.set()
        return

    set_child_mode(session)
    event.set()

    info = _('\nI will buy {} from {} to {}\n').format(addThousandSeparator(amount_to_buy), materials_names[resource], city['cityName'])
    setInfoSignal(session, info)
    try:
        do_it(session, city, offers, amount_to_buy)
    except Exception as e:
        msg = _('Error in:\n{}\nCause:\n{}').format(info, traceback.format_exc())
        sendToBot(session, msg)
    finally:
        session.logout()


def buy(session, city, offer, amount_to_buy):
    """
    Parameters
    ----------
    session : ikabot.web.session.Session
    city : dict
    offer : dict
    amount_to_buy : int
    """
    ships = int(math.ceil((Decimal(amount_to_buy) / Decimal(500))))
    data_dict = {
        'action': 'transportOperations',
        'function': 'buyGoodsAtAnotherBranchOffice',
        'cityId': offer['cityId'],
        'destinationCityId': offer['destinationCityId'],
        'oldView': 'branchOffice',
        'position': city['pos'],
        'avatar2Name': offer['jugadorAComprar'],
        'city2Name': offer['ciudadDestino'],
        'type': int(offer['type']),
        'activeTab': 'bargain',
        'transportDisplayPrice': 0,
        'premiumTransporter': 0,
        'capacity': 5,
        'max_capacity': 5,
        'jetPropulsion': 0,
        'transporters': ships,
        'backgroundView': 'city',
        'currentCityId': offer['cityId'],
        'templateView': 'takeOffer',
        'currentTab': 'bargain',
        'actionRequest': actionRequest,
        'ajax': 1
    }
    url = 'view=takeOffer&destinationCityId={}&oldView=branchOffice&activeTab=bargain&cityId={}&position={}&type={}&resource={}&backgroundView=city&currentCityId={}&templateView=branchOffice&actionRequest={}&ajax=1'.format(offer['destinationCityId'], offer['cityId'], offer['position'], offer['type'], offer['resource'], offer['cityId'], actionRequest)
    data = session.post(url)
    html = json.loads(data, strict=False)[1][1][1]
    hits = re.findall(r'"tradegood(\d)Price"\s*value="(\d+)', html)
    for hit in hits:
        data_dict['tradegood{}Price'.format(hit[0])] = int(hit[1])
        data_dict['cargo_tradegood{}'.format(hit[0])] = 0
    hit = re.search(r'"resourcePrice"\s*value="(\d+)', html)
    if hit:
        data_dict['resourcePrice'] = int(hit.group(1))
        data_dict['cargo_resource'] = 0
    resource = offer['resource']
    if resource == 'resource':
        data_dict['cargo_resource'] = amount_to_buy
    else:
        data_dict['cargo_tradegood{}'.format(resource)] = amount_to_buy
    session.post(payloadPost=data_dict)
    msg = _('I buy {} to {} from {}').format(addThousandSeparator(amount_to_buy), offer['ciudadDestino'], offer['jugadorAComprar'])
    sendToBotDebug(session, msg, debugON_buyResources)


def do_it(session, city, offers, amount_to_buy):
    """
    Parameters
    ----------
    session : ikabot.web.session.Session
    city : dict
    offers : list[dict]
    amount_to_buy : int
    """
    while True:
        for offer in offers:
            if amount_to_buy == 0:
                return
            if offer['amountAvailable'] == 0:
                continue

            ships_available = waitForArrival(session)
            storageCapacity = ships_available * 500
            buy_amount = min(amount_to_buy, storageCapacity, offer['amountAvailable'])

            amount_to_buy -= buy_amount
            offer['amountAvailable'] -= buy_amount
            buy(session, city, offer, buy_amount)
            # start from the beginning again, so that we always buy from the cheapest offers fisrt
            break
