import datetime
import os
import re

from glob import glob
from typing import Optional

from flask import Flask, Response, abort, send_from_directory, render_template
from markdown import markdown

basedir = os.path.abspath(os.path.join(os.path.realpath(__file__), '..', '..'))
templates_dir = os.path.join(basedir, 'templates')
static_dir = os.path.join(basedir, 'static')
pages_dir = os.path.join(static_dir, 'pages')
img_dir = os.path.join(static_dir, 'img')
css_dir = os.path.join(static_dir, 'css')
fonts_dir = os.path.join(static_dir, 'fonts')

app = Flask(__name__, template_folder=templates_dir)


def parse_page_title(page: str) -> str:
    if page.endswith('.md'):
        page = page[:-3]

    return page.replace('-', ' ')


def get_page_metadata(page: str) -> dict:
    if not page.endswith('.md'):
        page = page + '.md'

    if not os.path.isfile(os.path.join(pages_dir, page)):
        abort(404)

    metadata = {}
    with open(os.path.join(pages_dir, page), 'r') as f:
        metadata['uri'] = '/article/' + page[:-3]

        for line in f.readlines():
            if not line:
                continue

            if not (m := re.match(r'^\[//]: # \(([^:]+):\s*([^)]+)\)\s*$', line)):
                break

            if m.group(1) == 'published':
                metadata[m.group(1)] = datetime.date.fromisoformat(m.group(2))
            else:
                metadata[m.group(1)] = m.group(2)

    return metadata


def get_page(page: str, title: Optional[str] = None, skip_header: bool = False):
    if not page.endswith('.md'):
        page = page + '.md'

    metadata = get_page_metadata(page)
    with open(os.path.join(pages_dir, page), 'r') as f:
        return render_template('article.html',
                               title=title if title else metadata.get('title', 'Platypush - Blog'),
                               image=metadata.get('image'),
                               description=metadata.get('description'),
                               author=re.match(r'(.+?)\s+<([^>]+>)', metadata['author'])[1] if 'author' in metadata else None,
                               author_email=re.match(r'(.+?)\s+<([^>]+)>', metadata['author'])[2] if 'author' in metadata else None,
                               published=(metadata['published'].strftime('%b %d, %Y')
                                          if metadata.get('published') else None),
                               content=markdown(f.read(), extensions=['fenced_code', 'codehilite']),
                               skip_header=skip_header)


def get_pages(with_content: bool = False, skip_header: bool = False) -> list:
    return sorted([
        {
            'path': path,
            'content': get_page(path, skip_header=skip_header) if with_content else '',
            **get_page_metadata(os.path.basename(path)),
        }
        for path in glob(os.path.join(pages_dir, '*.md'))
    ], key=lambda page: page.get('published'), reverse=True)


@app.route('/', methods=['GET'])
def home_route():
    return render_template('index.html', pages=get_pages())


@app.route('/favicon.ico', methods=['GET'])
def favicon_route():
    return send_from_directory(img_dir, 'favicon.ico')


@app.route('/img/<img>', methods=['GET'])
def img_route(img: str):
    return send_from_directory(img_dir, img)


@app.route('/css/<style>', methods=['GET'])
def css_route(style: str):
    return send_from_directory(css_dir, style)


@app.route('/fonts/<file>', methods=['GET'])
def fonts_route(file: str):
    return send_from_directory(fonts_dir, file)


@app.route('/article/<article>', methods=['GET'])
def article_route(article: str):
    return get_page(article)


@app.route('/rss', methods=['GET'])
def rss_route():
    pages = get_pages(with_content=True, skip_header=True)

    return Response('''<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0" xmlns:media="http://search.yahoo.com/mrss/">
    <channel>
        <title>Platypush blog feeds</title> 
        <link>http://blog.platypush.tech</link>
        <description>Insights and inspirational projects using Platypush as an automation platform</description> 
        <category>Programming, automation, Python, machine learning, IoT, smart home</category>
        <image>
            <url>https://git.platypush.tech/uploads/-/system/appearance/header_logo/1/icon-256.png</url>
            <title>Platypush</title>
            <link>https://git.platypush.tech</link>
        </image> 
        <pubDate>{last_pub_date}</pubDate> 
        <language>en-us</language>

        {items}
    </channel>
</rss>'''.format(
        last_pub_date=pages[0]['published'].strftime('%a, %d %b %Y %H:%M:%S GMT'),
        items='\n\n'.join([
            '''
            <item>
                <title>{title}</title>
                <link>https://blog.platypush.tech{link}</link>
                <pubDate>{published}</pubDate>
                <description><![CDATA[{content}]]></description>
                <media:content medium="image" url="https://blog.platypush.tech{image}" width="200" height="150" />
            </item>
            '''.format(
                title=page.get('title', '[No Title]'),
                link=page.get('uri', ''),
                published=page['published'].strftime('%a, %d %b %Y %H:%M:%S GMT') if 'published' in page else '',
                content=page.get('content', ''),
                image=page.get('image', ''),
            )
            for page in pages
        ]),
    ), mimetype='application/rss+xml')
