import {Controller, view, Inject, Injectable, collect, plaintext, Config, Maybe} from '@extollo/lib'
import {Home} from './Home.controller'
import {Blog as BlogService} from '../../services/Blog.service'
import {BlogPost} from '../../services/blog/AbstractBlog.service'

/**
 * Blog Controller
 * ------------------------------------
 * Put some description here.
 */
@Injectable()
export class Blog extends Controller {
    @Inject()
    protected readonly blog!: BlogService

    @Inject()
    protected readonly config!: Config

    public async index() {
        const home = <Home> this.make(Home)
        const posts = await this.blog.getAllPosts()
        return view('blog:index', {
            ...home.getThemeCSS(),
            ...this.getBlogData(),
            title: 'Garrett\'s Blog',
            posts: posts.take(10).toArray(),
        })
    }

    public async post() {
        const home = <Home> this.make(Home)
        const slug = this.request.safe('slug').string()
        const post = await this.blog.getPost(slug)
        if ( !post ) {
            return view('blog:404', {
                ...home.getThemeCSS(),
                ...this.getBlogData(),
                title: 'Post Not Found',
                slug,
            })
        }

        return view('blog:post', {
            ...home.getThemeCSS(),
            ...this.getBlogData(),
            ...this.getChorusData(post),
            post,
            title: post.title,
            renderedPost: await this.blog.renderPost(post.slug),
        })
    }

    private getChorusData(post: BlogPost): {}|{ chorusThread: string, chorusAddress: string } {
        if ( !post.shortId ) {
            return {}
        }

        if ( !this.config.get('server.chorus.baseUrl') ) {
            return {}
        }

        const template = this.config.get('server.chorus.thread.template')
        const idPrefix = this.config.get('server.chorus.thread.idPrefix')
        if ( !template || !idPrefix ) {
            return {}
        }

        const chorusThread = `${idPrefix}blog${post.shortId}`
        const chorusAddress = String(template).replaceAll('%ID%', chorusThread)

        return { chorusThread, chorusAddress }
    }

    public async archive() {
        const home = <Home> this.make(Home)
        const postsByYear = await this.blog.getAllPosts()
            .then(ps => ps.groupBy(p => p.date.getFullYear()))

        return view('blog:archive', {
            ...home.getThemeCSS(),
            ...this.getBlogData(),
            title: 'Archive',
            postsByYear,
            postYears: collect(Object.keys(postsByYear)).sortDesc().toArray(),
        })
    }

    public async tags() {
        const home = <Home> this.make(Home)
        const counts = {} as Record<string, number>
        await this.blog.getAllPosts()
            .then(ps => ps.each(post => {
                post.tags.some(tag => {
                    if ( !counts[tag] ) counts[tag] = 1
                    else counts[tag] += 1
                })
            }))

        return view('blog:tags', {
            ...home.getThemeCSS(),
            ...this.getBlogData(),
            title: 'Tags',
            counts,
            tags: collect(Object.keys(counts)).sort().toArray(),
        })
    }

    public async tag() {
        const home = <Home> this.make(Home)
        const tag = this.request.safe('tag').string()
        const posts = await this.blog.getAllPosts()
            .then(ps => ps.filter(p => p.tags.includes(tag)).sortByDesc('date'))

        console.log('tag posts', posts)

        return view('blog:tag', {
            ...home.getThemeCSS(),
            ...this.getBlogData(),
            title: `#${tag}`,
            posts: posts.toArray(),
            tag,
        })
    }

    public async feeds() {
        const home = <Home> this.make(Home)
        const subsByCategory = await this.blog.getSubs()
            .then(ss => ss.groupBy('category'))
        const categories = collect(Object.keys(subsByCategory)).sort().toArray()

        return view('blog:feeds', {
            ...home.getThemeCSS(),
            ...this.getBlogData(),
            title: 'An RSS Manifesto',
            subsByCategory,
            categories,
        })
    }

    public async rss() {
        const feed = await this.blog.getFeed()
        return plaintext(feed.rss2()).contentType('application/rss+xml; charset=UTF-8')
    }

    public async atom() {
        const feed = await this.blog.getFeed()
        return plaintext(feed.atom1()).contentType('application/atom+xml; charset=UTF-8')
    }

    public async json() {
        const feed = await this.blog.getFeed()
        return plaintext(feed.json1()).contentType('application/feed+json; charset=UTF-8')
    }

    public getBlogData(): any {
        let chorusUrl = String(this.config.get('server.chorus.baseUrl') || '')
        if ( chorusUrl && !chorusUrl.endsWith('/') ) chorusUrl += '/'

        return {
            chorusUrl,
            blogUrl: (post: BlogPost): string => this.blog.getUrl(post),
            blogDate: (date: Date): string => {
                const year = date.getFullYear()
                let month = String(date.getMonth() + 1)
                if ( month.length < 2 ) month = `0${month}`
                let day = String(date.getDate())
                if ( day.length < 2 ) day = `0${day}`
                return `${year}-${month}-${day}`
            },
        }
    }

}
