from .autopath import do_autopath
do_autopath()
from .config import config_type, get_config, value_list, global_owner

import warnings, sys
import pytest

from tiramisu import Config, DomainnameOption, EmailOption, URLOption, OptionDescription
from tiramisu.error import ValueWarning
from tiramisu.i18n import _
from tiramisu.storage import list_sessions
from .config import event_loop


@pytest.mark.asyncio
async def test_domainname(config_type):
    d = DomainnameOption('d', '')
    f = DomainnameOption('f', '', allow_without_dot=True)
    g = DomainnameOption('g', '', allow_ip=True)
    h = DomainnameOption('h', '', allow_cidr_network=True)
    od = OptionDescription('a', '', [d, f, g, h])
    async with await Config(od) as cfg:
        await cfg.property.read_write()
        cfg = await get_config(cfg, config_type)
        #
        await cfg.option('d').value.set('toto.com')
        with pytest.raises(ValueError):
            await cfg.option('d').value.set('toto')
        await cfg.option('d').value.set('toto3.com')
        with pytest.raises(ValueError):
            await cfg.option('d').value.set('toto_super.com')
        await cfg.option('d').value.set('toto-.com')
        with pytest.raises(ValueError):
            await cfg.option('d').value.set('toto..com')
        #
        await cfg.option('f').value.set('toto.com')
        await cfg.option('f').value.set('toto')
        await cfg.option('f').value.set('domainnametoolongthathavemorethanmaximumsizeforatruedomainnamea')
        with pytest.raises(ValueError):
            await cfg.option('f').value.set('domainnametoolongthathavemorethanmaximumsizeforatruedomainnamean')
        await cfg.option('f').value.set('domainnametoolongthathavemorethanmaximumsizeforatruedomainnamea.nd')
        await cfg.option('f').value.set('domainnametoolongthathavemorethanmaximumsizeforatruedomainnamea.nditsnoteasytogeneratesolongdomainnamewithoutrepeatdomainnameto.olongthathavemorethanmaximumsizeforatruedomainnameanditsnoteas.ytogeneratesolongdomainnamewithoutrepeatbutimnotabletodoitnowie')
        with pytest.raises(ValueError):
            await cfg.option('d').value.set('domainnametoolongthathavemorethanmaximumsizeforatruedomainnamea.nditsnoteasytogeneratesolongdomainnamewithoutrepeatdomainnameto.olongthathavemorethanmaximumsizeforatruedomainnameanditsnoteas.ytogeneratesolongdomainnamewithoutrepeatbutimnotabletodoitnowien')
        await cfg.option('f').value.set('d')
        await cfg.option('f').value.set('d.t')
        #
        if config_type != 'tiramisu-api':
            # FIXME
            with pytest.raises(ValueError):
                await cfg.option('f').value.set('192.168.1.1')
        with pytest.raises(ValueError):
            await cfg.option('f').value.set('192.168.1.0/24')
        #
        await cfg.option('g').value.set('toto.com')
        await cfg.option('g').value.set('192.168.1.0')
        await cfg.option('g').value.set('192.168.1.29')
        with pytest.raises(ValueError):
            await cfg.option('g').value.set('192.168.1.0/24')
        #
        await cfg.option('h').value.set('toto.com')
        if config_type != 'tiramisu-api':
            # FIXME
            with pytest.raises(ValueError):
                await cfg.option('h').value.set('192.168.1.0')
            with pytest.raises(ValueError):
                await cfg.option('h').value.set('192.168.1.29')
        # it's a network address
        await cfg.option('h').value.set('192.168.1.0/24')
        # but not here
        with pytest.raises(ValueError):
            await cfg.option('h').value.set('192.168.1.1/24')
    assert not await list_sessions()


@pytest.mark.asyncio
async def test_domainname_upper(config_type):
    d = DomainnameOption('d', '')
    od = OptionDescription('a', '', [d])
    async with await Config(od) as cfg:
        await cfg.property.read_write()
        cfg = await get_config(cfg, config_type)
        await cfg.option('d').value.set('toto.com')
        msg = _('some characters are uppercase')
        has_error = False
        try:
            await cfg.option('d').value.set('TOTO.COM')
        except ValueError as err:
            if config_type != 'tiramisu-api':
                # FIXME
                assert msg in str(err)
            has_error = True
        assert has_error is True
        has_error = False
        try:
            await cfg.option('d').value.set('toTo.com')
        except ValueError as err:
            if config_type != 'tiramisu-api':
                # FIXME
                assert msg in str(err)
            has_error = True
        assert has_error is True
    assert not await list_sessions()


@pytest.mark.asyncio
async def test_domainname_warning(config_type):
    d = DomainnameOption('d', '', warnings_only=True)
    f = DomainnameOption('f', '', allow_without_dot=True, warnings_only=True)
    g = DomainnameOption('g', '', allow_ip=True, warnings_only=True)
    od = OptionDescription('a', '', [d, f, g])
    warnings.simplefilter("always", ValueWarning)
    async with await Config(od) as cfg:
        await cfg.property.read_write()
        cfg = await get_config(cfg, config_type)
        await cfg.option('d').value.set('toto.com')
        with pytest.raises(ValueError):
            await cfg.option('d').value.set('toto')
        await cfg.option('d').value.set('toto3.com')
        if config_type != 'tiramisu-api':
            # FIXME
            with warnings.catch_warnings(record=True) as w:
                await cfg.option('d').value.set('toto_super.com')
            assert len(w) == 1
        with warnings.catch_warnings(record=True) as w:
            await cfg.option('d').value.set('toto-.com')
        assert len(w) == 0
        with pytest.raises(ValueError):
            await cfg.option('d').value.set('toto..com')
        #
        await cfg.option('f').value.set('toto.com')
        await cfg.option('f').value.set('toto')
        await cfg.option('f').value.set('domainnametoolongthathavemorethanmaximumsizeforatruedomainnamea')
        with pytest.raises(ValueError):
            await cfg.option('f').value.set('domainnametoolongthathavemorethanmaximumsizeforatruedomainnamean')
        await cfg.option('f').value.set('domainnametoolongthathavemorethanmaximumsizeforatruedomainnamea.nd')
        await cfg.option('f').value.set('domainnametoolongthathavemorethanmaximumsizeforatruedomainnamea.nditsnoteasytogeneratesolongdomainnamewithoutrepeatdomainnameto.olongthathavemorethanmaximumsizeforatruedomainnameanditsnoteas.ytogeneratesolongdomainnamewithoutrepeatbutimnotabletodoitnowie')
        if config_type != 'tiramisu-api':
            # FIXME
            with pytest.raises(ValueError):
                await cfg.option('f').value.set('domainnametoolongthathavemorethanmaximumsizeforatruedomainname.nditsnoteasytogeneratesolongdomainnamewithoutrepeatdomainnamet.olongthathavemorethanmaximumsizeforatruedomainnameanditsnotea.ytogeneratesolongdomainnamewithoutrepeatbutimnotabletodoitnowie.xxxx')
        await cfg.option('f').value.set('d')
        await cfg.option('f').value.set('d.t')
        #
        if config_type != 'tiramisu-api':
            # FIXME
            with pytest.raises(ValueError):
                await cfg.option('f').value.set('192.168.1.1')
        await cfg.option('g').value.set('toto.com')
        await cfg.option('g').value.set('192.168.1.0')
        await cfg.option('g').value.set('192.168.1.29')
    assert not await list_sessions()


@pytest.mark.asyncio
async def test_special_domain_name(config_type):
    """domain name option that starts with a number or not
    """
    d = DomainnameOption('d', '')
    e = DomainnameOption('e', '', type='netbios')
    od = OptionDescription('a', '', [d, e])
    async with await Config(od) as cfg:
        await cfg.property.read_write()
        cfg = await get_config(cfg, config_type)
        await cfg.option('d').value.set('1toto.com')
        await cfg.option('d').value.set('123toto.com')
        await cfg.option('e').value.set('toto')
        await cfg.option('e').value.set('1toto')
    assert not await list_sessions()


@pytest.mark.asyncio
async def test_domainname_netbios(config_type):
    d = DomainnameOption('d', '', type='netbios')
    e = DomainnameOption('e', '', "toto", type='netbios')
    od = OptionDescription('a', '', [d, e])
    async with await Config(od) as cfg:
        await cfg.property.read_write()
        cfg = await get_config(cfg, config_type)
        with pytest.raises(ValueError):
            await cfg.option('d').value.set('toto.com')
        await cfg.option('d').value.set('toto')
        with pytest.raises(ValueError):
            await cfg.option('d').value.set('domainnametoolong')
    assert not await list_sessions()


@pytest.mark.asyncio
async def test_domainname_hostname(config_type):
    d = DomainnameOption('d', '', type='hostname')
    e = DomainnameOption('e', '', "toto", type='hostname')
    od = OptionDescription('a', '', [d, e])
    async with await Config(od) as cfg:
        await cfg.property.read_write()
        cfg = await get_config(cfg, config_type)
        with pytest.raises(ValueError):
            await cfg.option('d').value.set('toto.com')
        await cfg.option('d').value.set('toto')
        await cfg.option('d').value.set('domainnametoolong')
    assert not await list_sessions()


@pytest.mark.asyncio
async def test_email(config_type):
    e = EmailOption('e', '')
    od = OptionDescription('a', '', [e])
    async with await Config(od) as cfg:
        await cfg.property.read_write()
        cfg = await get_config(cfg, config_type)
        await cfg.option('e').value.set('foo-bar.baz@example.com')
        await cfg.option('e').value.set('root@foo.com')
        await cfg.option('e').value.set('root@domain')
        with pytest.raises(ValueError):
            await cfg.option('e').value.set(1)
        with pytest.raises(ValueError):
            await cfg.option('e').value.set('root')
        with pytest.raises(ValueError):
            await cfg.option('e').value.set('root[]@domain')
    assert not await list_sessions()


@pytest.mark.asyncio
async def test_url(config_type):
    u = URLOption('u', '')
    od = OptionDescription('a', '', [u])
    async with await Config(od) as cfg:
        await cfg.property.read_write()
        cfg = await get_config(cfg, config_type)
        await cfg.option('u').value.set('http://foo.com')
        await cfg.option('u').value.set('https://foo.com')
        await cfg.option('u').value.set('https://foo.com/')
        with pytest.raises(ValueError):
            await cfg.option('u').value.set(1)
        if config_type != 'tiramisu-api':
            # FIXME
            with pytest.raises(ValueError):
                await cfg.option('u').value.set('ftp://foo.com')
            with pytest.raises(ValueError):
                await cfg.option('u').value.set('foo.com')
            with pytest.raises(ValueError):
                await cfg.option('u').value.set(':/foo.com')
            with pytest.raises(ValueError):
                await cfg.option('u').value.set('foo.com/http://')
        await cfg.option('u').value.set('https://foo.com/index.html')
        await cfg.option('u').value.set('https://foo.com/index.html?var=value&var2=val2')
        if config_type != 'tiramisu-api':
            # FIXME
            with pytest.raises(ValueError):
                await cfg.option('u').value.set('https://foo.com/index\\n.html')
        await cfg.option('u').value.set('https://foo.com:8443')
        await cfg.option('u').value.set('https://foo.com:8443/')
        await cfg.option('u').value.set('https://foo.com:8443/index.html')
        if config_type != 'tiramisu-api':
            # FIXME
            with pytest.raises(ValueError):
                await cfg.option('u').value.set('https://foo.com:84438989')
        await cfg.option('u').value.set('https://foo.com:8443/INDEX')
        if config_type != 'tiramisu-api':
            # FIXME
            with pytest.raises(ValueError):
                await cfg.option('u').value.set('https://FOO.COM:8443')
    assert not await list_sessions()