#!/usr/bin/python
# -*- coding: utf-8 -*-

# --------------------------------------------------------------------------- #
#                                                                             #
#    Plugin for iSida Jabber Bot                                              #
#    Copyright (C) diSabler <dsy@dsy.name>                                    #
#    Fixed by: Using CBR API instead of rbc.ru                               #
#                                                                             #
#    This program is free software: you can redistribute it and/or modify     #
#    it under the terms of the GNU General Public License as published by     #
#    the Free Software Foundation, either version 3 of the License, or        #
#    (at your option) any later version.                                      #
#                                                                             #
#    This program is distributed in the hope that it will be useful,          #
#    but WITHOUT ANY WARRANTY; without even the implied warranty of           #
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            #
#    GNU General Public License for more details.                             #
#                                                                             #
#    You should have received a copy of the GNU General Public License        #
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.    #
#                                                                             #
# --------------------------------------------------------------------------- #

import xml.etree.ElementTree as ET
import urllib.request
import re
import time

# Кэш для курсов валют (обновляется раз в час)
_currency_cache = {
    'data': {},
    'timestamp': 0,
    'date': ''
}

# Список поддерживаемых валют (коды ЦБ РФ)
CBR_CURRENCIES = [
    'AUD', 'AZN', 'AMD', 'BYN', 'BGN', 'BRL', 'HUF', 'HKD',
    'DKK', 'USD', 'EUR', 'INR', 'KZT', 'CAD', 'KGS', 'CNY',
    'MDL', 'NOK', 'PLN', 'RON', 'XDR', 'SGD', 'TJS', 'TRY',
    'TMT', 'UZS', 'UAH', 'GBP', 'CZK', 'SEK', 'CHF', 'ZAR',
    'KRW', 'JPY', 'RUB'
]

def get_cbr_rates():
    """
    Получает курсы валют с сайта ЦБ РФ.
    Возвращает словарь {код_валюты: курс_к_рублю}
    """
    global _currency_cache

    # Проверяем кэш (обновляем раз в час)
    if time.time() - _currency_cache['timestamp'] < 3600:
        return _currency_cache['data']

    try:
        url = 'http://www.cbr.ru/scripts/XML_daily.asp'
        req = urllib.request.Request(url, headers={'User-Agent': 'Mozilla/5.0'})
        with urllib.request.urlopen(req, timeout=10) as response:
            body = response.read().decode('windows-1251', errors='replace')

        root = ET.fromstring(body)

        rates = {}
        for valute in root.findall('Valute'):
            charcode = valute.find('CharCode').text
            value = valute.find('Value').text.replace(',', '.')
            nominal = int(valute.find('Nominal').text)

            # Сохраняем курс за 1 единицу валюты (в рублях)
            rates[charcode] = float(value) / nominal

        # Добавляем рубль
        rates['RUB'] = 1.0

        # Сохраняем в кэш
        _currency_cache['data'] = rates
        _currency_cache['timestamp'] = time.time()
        _currency_cache['date'] = root.find('Date').text if root.find('Date') is not None else ''

        return rates

    except Exception as e:
        # Если ошибка, возвращаем старый кэш или пустой словарь
        return _currency_cache['data'] if _currency_cache['data'] else {}

def convert_currency(amount, from_currency, to_currency):
    """
    Конвертирует сумму из одной валюты в другую через рубль.
    """
    rates = get_cbr_rates()

    if not rates:
        return None, None

    if from_currency not in rates:
        return None, 'from'

    if to_currency not in rates:
        return None, 'to'

    # Конвертируем через рубль
    result = amount * rates[from_currency] / rates[to_currency]

    return result, None

def get_currency_name(code):
    """
    Возвращает русское название валюты по коду.
    """
    names = {
        'AUD': 'Австралийский доллар',
        'AZN': 'Азербайджанский манат',
        'AMD': 'Армянский драм',
        'BYN': 'Белорусский рубль',
        'BGN': 'Болгарский лев',
        'BRL': 'Бразильский реал',
        'HUF': 'Венгерский форинт',
        'HKD': 'Гонконгский доллар',
        'DKK': 'Датская крона',
        'USD': 'Доллар США',
        'EUR': 'Евро',
        'INR': 'Индийская рупия',
        'KZT': 'Казахстанский тенге',
        'CAD': 'Канадский доллар',
        'KGS': 'Киргизский сом',
        'CNY': 'Китайский юань',
        'MDL': 'Молдавский лей',
        'NOK': 'Норвежская крона',
        'PLN': 'Польский злотый',
        'RON': 'Румынский лей',
        'XDR': 'СДР (спец. права заимствования)',
        'SGD': 'Сингапурский доллар',
        'TJS': 'Таджикский сомони',
        'TRY': 'Турецкая лира',
        'TMT': 'Туркменский манат',
        'UZS': 'Узбекский сум',
        'UAH': 'Украинская гривна',
        'GBP': 'Фунт стерлингов',
        'CZK': 'Чешская крона',
        'SEK': 'Шведская крона',
        'CHF': 'Швейцарский франк',
        'ZAR': 'Южноафриканский рэнд',
        'KRW': 'Южнокорейский вон',
        'JPY': 'Японская иена',
        'RUB': 'Российский рубль'
    }
    return names.get(code, code)

def currency_converter(type, jid, nick, text):
    """
    Основная функция конвертации валют.
    Форматы:
    - convert 100 USD EUR
    - convert 100 USD в EUR
    - convert list - список доступных валют
    """
    if not text:
        msg = L('Error in parameters. Read the help about command.', '%s/%s' % (jid, nick))
        send_msg(type, jid, nick, msg)
        return

    text = text.strip()

    # Вывод списка валют
    if text.upper() == 'LIST':
        currencies = sorted(CBR_CURRENCIES)
        msg = L('Available currencies:', '%s/%s' % (jid, nick))
        msg += '\n' + ', '.join(currencies)
        send_msg(type, jid, nick, msg)
        return

    # Заменяем символы валют на коды
    replacements = (
        (u'€', 'EUR'), (u'$', 'USD'), (u'¥', 'JPY'),
        (u'£', 'GBP'), (',', '.'), (u'в', '')
    )

    for old, new in replacements:
        text = text.replace(old, new)

    # Парсим сумму
    numbers = re.findall(r'[\d.]+', text)
    if not numbers:
        msg = L('Error in parameters. Read the help about command.', '%s/%s' % (jid, nick))
        send_msg(type, jid, nick, msg)
        return

    amount = float(numbers[0])

    # Ищем коды валют (3-4 буквы)
    codes = re.findall(r'[A-Z]{3,4}', text)
    from_currency = None
    to_currency = None

    # Первый код - исходная валюта
    for code in codes:
        if code in CBR_CURRENCIES:
            if from_currency is None:
                from_currency = code
            elif to_currency is None:
                to_currency = code
                break

    if not from_currency or not to_currency:
        msg = L('Error in parameters. Read the help about command.', '%s/%s' % (jid, nick))
        send_msg(type, jid, nick, msg)
        return

    # Выполняем конвертацию
    result, error = convert_currency(amount, from_currency, to_currency)

    if error == 'from':
        msg = L('Currency %s not supported.', '%s/%s' % (jid, nick)) % from_currency
    elif error == 'to':
        msg = L('Currency %s not supported.', '%s/%s' % (jid, nick)) % to_currency
    elif result is None:
        msg = L('Service temporarily unavailable. Try again later.', '%s/%s' % (jid, nick))
    else:
        # Форматируем результат
        from_name = get_currency_name(from_currency)
        to_name = get_currency_name(to_currency)
        date = _currency_cache['date'] if _currency_cache['date'] else L('today', '%s/%s' % (jid, nick))

        msg = '%g %s (%s) = %g %s (%s) | %s' % (
            amount, from_currency, from_name,
            result, to_currency, to_name,
            L('Rate from CBR on %s', '%s/%s' % (jid, nick)) % date
        )

    send_msg(type, jid, nick, msg)

global execute

execute = [(3, 'convert', currency_converter, 2, 'Currency converter\nconvert 100 USD EUR\nconvert list')]
