from datetime import datetime
from uuid import uuid4
from monero.address import address
from sqlalchemy import Column, Integer, BigInteger, DateTime, String
from sqlalchemy.sql import func
from app.factory import db
from app.library.crypto import monero, wownero
from app import config


def rand_id():
    return uuid4().hex

class Swap(db.Model):
    __tablename__ = 'swaps'

    # Meta
    id = db.Column(db.String(80), primary_key=True, default=rand_id)
    date = db.Column(db.DateTime, server_default=func.now())
    wow_to_xmr = db.Column(db.Boolean)
    wow_price_ausd = db.Column(db.Integer)
    xmr_price_ausd = db.Column(db.Integer)
    swap_address = db.Column(db.String(150), unique=True)
    swap_address_index = db.Column(db.Integer, unique=True)
    return_wow_address = db.Column(db.String(150))
    return_xmr_address = db.Column(db.String(150))
    completed = db.Column(db.Boolean, default=False)
    completed_date = db.Column(db.DateTime, nullable=True)

    # Receive details
    receive_amount_atomic = db.Column(db.BigInteger)
    funds_received = db.Column(db.Boolean, default=False)
    receive_tx_id = db.Column(db.String(150), nullable=True)

    # Send details
    fee_amount_atomic = db.Column(db.BigInteger)
    send_amount_atomic = db.Column(db.BigInteger)
    send_tx_id = db.Column(db.String(150), nullable=True)
    funds_sent = db.Column(db.Boolean, default=False)

    def __repr__(self):
        return self.id

    def show_details(self):
        if self.wow_to_xmr:
            r = wownero
            s = monero
            r_unit = 'WOW'
            s_unit = 'XMR'
        else:
            r = monero
            s = wownero
            r_unit = 'XMR'
            s_unit = 'WOW'
        receive_amount = r.as_real(r.from_atomic(self.receive_amount_atomic))
        send_amount = s.as_real(s.from_atomic(self.send_amount_atomic))
        return {
            'id': self.id,
            'date': self.date,
            'wow_to_xmr': self.wow_to_xmr,
            'wow_price_ausd': self.wow_price_ausd,
            'xmr_price_ausd': self.xmr_price_ausd,
            'swap_address': self.swap_address,
            'swap_address_index': self.swap_address_index,
            'return_wow_address': self.return_wow_address,
            'return_xmr_address': self.return_xmr_address,
            'completed': self.completed,
            'completed_date': self.completed_date,
            'receive_amount_atomic': self.receive_amount_atomic,
            'funds_received': self.funds_received,
            'receive_tx_id': self.receive_tx_id,
            'fee_amount_atomic': self.fee_amount_atomic,
            'send_amount_atomic': self.send_amount_atomic,
            'send_tx_id': self.send_tx_id,
            'funds_sent': self.funds_sent,
            'receive': f'{receive_amount} {r_unit}',
            'send': f'{send_amount} {s_unit}',
            'fee': f'{s.as_real(s.from_atomic(self.fee_amount_atomic))} {s_unit}',
            'hours_completed': self.hours_elapsed(since_completed=True),
            'hours_active': self.hours_elapsed(),
            'receive_unit': r_unit,
            'send_unit': s_unit
        }


    def hours_elapsed(self, since_completed=False):
        now = datetime.utcnow()
        if since_completed:
            if self.completed_date:
                diff = now - self.completed_date
            else:
                return 0
        else:
            diff = now - self.date
        return diff.total_seconds() / 60 / 60

    def days_completed(self):
        if self.completed_date:
            now = datetime.now()
            diff = now - self.completed_date
            return diff.days
        else:
            return 0

    def receive_coin(self):
        if self.wow_to_xmr:
            return 'wow'
        else:
            return 'xmr'

    def send_coin(self):
        if self.wow_to_xmr:
            return 'xmr'
        else:
            return 'wow'

    def to_ausd(self, amount):
        return int(amount * 1000000)

    def from_ausd(self, amount):
        return amount / 1000000

    def validate_swap_worth(self, worth):
        worth_ausd = self.to_ausd(worth)
        min = self.to_ausd(config.SWAP_MIN_USD)
        max = self.to_ausd(config.SWAP_MAX_USD)
        if worth_ausd < min:
            return (False, 'Too low')
        elif worth_ausd > max:
            return (False, 'Too high')
        else:
            return (True, '')

    def validate_wow_address(self, wow_address):
        # lol yolo
        if len(wow_address) != 97:
            return False
        else:
            return True

    def validate_xmr_address(self, xmr_address):
        try:
            address(xmr_address)
            return True
        except:
            return False
