import aiofiles
import os
import re

from typing import AsyncIterable, Optional
from aiopath import AsyncPath

from localhttps.cert.ca import CertificationAuthority
from localhttps.cert.cert import Certificate

class App:
    _data_path: AsyncPath

    def __init__(self, data_path: AsyncPath) -> None:
        self._data_path = data_path

    async def list_ca(self) -> AsyncIterable[CertificationAuthority]:
        root = self._data_path/'CertificationAuthorities'

        async for file in root.glob('*.pem'):
            yield CertificationAuthority(root, os.path.splitext(file.name)[0])

    def ca(self, name: str = 'default') -> CertificationAuthority:
        return CertificationAuthority(self._data_path/'CertificationAuthorities', name)

    async def list_certs(self, ca: Optional[CertificationAuthority] = None) -> AsyncIterable[Certificate]:
        if ca is None:
            ca = self.ca()

        root = self._data_path/'Certificates'/ca.name

        async for file in root.glob('*.conf'):
            name = os.path.splitext(file.name)[0]
            domain = name

            async with aiofiles.open(file) as f:
                if await f.readline() == '# Generated by LocalHTTPS\n':
                    match = re.match('^# domain=(.*)\n$', await f.readline())
                    if match is not None:
                        domain = match.group(1)

            yield Certificate(
                authority=ca,
                root_path=root,
                name=name,
                domain=domain
            )

    def cert(self, name: str, domain: str, ca: Optional[CertificationAuthority] = None) -> Certificate:
        if ca is None:
            ca = self.ca()

        return Certificate(
            authority=ca,
            root_path=self._data_path/'Certificates'/ca.name,
            name=name,
            domain=domain,
        )

    async def generate_nginx_config(self, cert: Certificate, out_path: AsyncPath):
        await out_path.write_text(f'''
ssl_certificate {await cert.crt_path.absolute()};
ssl_certificate_key {await cert.key_path.absolute()};
'''.strip())

    async def generate_universal_nginx_config(self, ca: CertificationAuthority, out_path: AsyncPath):
        key_path_prefix = await (self._data_path/'Certificates'/ca.name).absolute()
        await out_path.write_text(f'''
ssl_certificate {key_path_prefix}/$ssl_server_name.crt;
ssl_certificate_key {key_path_prefix}/$ssl_server_name.key;
'''.strip())
