#!/usr/bin/env bash
set -euo pipefail

die() {
    echo "Error: $1" >&2
    exit 1
}

# Check required commands
command -v curl       >/dev/null || die "curl required"
command -v xmlstarlet >/dev/null || die "xmlstarlet required"
command -v awk         >/dev/null || die "awk required"
command -v sed         >/dev/null || die "sed required"
command -v date        >/dev/null || die "date required"

readonly html_file="index.html"
readonly rss_file="rss.xml"
readonly site_conf="site.conf"
readonly feeds_file="feeds.csv"

tmp=$(mktemp)
sorted=$(mktemp)
items_html=$(mktemp)
items_rss=$(mktemp)
index_tmp=$(mktemp)
rss_tmp=$(mktemp)

trap 'rm -f "$tmp" "$sorted" "$items_html" "$items_rss" "$index_tmp" "$rss_tmp"' EXIT

# Check files
[[ -f "$site_conf" ]]  || die "missing $site_conf"
[[ -f "$feeds_file" ]] || die "missing $feeds_file"

# ----------------------------------------------------------------------
# Configuration
# ----------------------------------------------------------------------

site_title=""
site_description=""
site_author=""
site_language="en-GB"
date_format="%-d %b %Y"
url_base=""

while IFS=':' read -r k v; do
    k=$(xargs <<< "$k")
    v=$(xargs <<< "$v")

    case "$k" in
        title)       site_title="$v" ;;
        description) site_description="$v" ;;
        author)      site_author="$v" ;;
        language)    site_language="$v" ;;
        date_format) date_format="$v" ;;
        url)         url_base="$v" ;;
    esac
done < "$site_conf"

[[ -n "$site_title" ]]  || die "title missing from site.conf"
[[ -n "$url_base" ]]    || die "url missing from site.conf"

url_base="${url_base%/}"

generated=$(date -Ru)

# ----------------------------------------------------------------------
# Helpers
# ----------------------------------------------------------------------

escape_html() {
    sed \
        -e 's/&/\&amp;/g' \
        -e 's/</\&lt;/g' \
        -e 's/>/\&gt;/g' \
        -e 's/"/\&quot;/g'
}

# ----------------------------------------------------------------------
# Fetch and extract feeds
# ----------------------------------------------------------------------

while IFS='|' read -r feed_url author class; do
    [[ -z "$feed_url" || "$feed_url" == \#* ]] && continue

    echo "Fetching: $feed_url"

    feed=$(mktemp)

    if curl -fsS \
        --connect-timeout 5 \
        --max-time 15 \
        "$feed_url" \
        -o "$feed"
    then
        xmlstarlet sel -T -t \
            -m '//*[local-name()="item" or local-name()="entry"]' \
            -v 'normalize-space((*[local-name()="pubDate" or local-name()="updated" or local-name()="published"])[1])' \
            -o '|' \
            -v 'normalize-space(*[local-name()="title"][1])' \
            -o '|' \
            -v 'normalize-space((*[local-name()="link"][@href]/@href | *[local-name()="link"][not(@href)] | *[local-name()="enclosure"]/@url)[1])' \
            -n \
            "$feed" 2>/dev/null |
        awk -F'|' -v a="$author" -v c="$class" '
            NF >= 3 && $1 && $2 && $3 {
                print $1 "|" $2 "|" $3 "|" a "|" c
            }
        ' >> "$tmp" || true
    fi

    rm -f "$feed"

done < "$feeds_file"

[[ -s "$tmp" ]] || die "no feed items found"

echo "Building HTML and RSS"

# ----------------------------------------------------------------------
# Sort items by date
# ----------------------------------------------------------------------

awk -F'|' '
{
    cmd="date -d \"" $1 "\" +%s 2>/dev/null"
    cmd | getline t
    close(cmd)

    if (!t)
        t=0

    print t "|" $0
}
' "$tmp" |
sort -nr |
cut -d'|' -f2- > "$sorted"

# ----------------------------------------------------------------------
# Render items
# ----------------------------------------------------------------------

while IFS='|' read -r date title link author class; do
    printf 'Generating: %s\n' "$title" >&2
    pretty_date=$(date -d "$date" +"$date_format" 2>/dev/null || echo "$date")
    rss_date=$(date -R -d "$date" 2>/dev/null || echo "$date")
    date=$(printf '%s' "$date" | escape_html)
    pretty_date=$(printf '%s' "$pretty_date" | escape_html)
    title=$(printf '%s' "$title" | escape_html)
    link=$(printf '%s' "$link" | escape_html)
    author=$(printf '%s' "$author" | escape_html)
    class=$(printf '%s' "$class" | escape_html)

    # Built-in compact HTML template
    cat >> "$items_html" <<EOF
<div class="item $class">
<span class="class">$class</span>
<span class="delim delim1">•</span>
<time datetime="$date">$pretty_date</time>
<span class="delim delim2">•</span>
<a href="$link">$title</a>
<span class="delim delim3">•</span>
<span class="author">$author</span>
</div>
EOF

    # Built-in RSS item template
    cat >> "$items_rss" <<EOF
<item>
<title>$title</title>
<pubDate>$rss_date</pubDate>
<link>$link</link>
<guid isPermaLink="true">$link</guid>
</item>
EOF

done < "$sorted"

# ----------------------------------------------------------------------
# Build HTML
# ----------------------------------------------------------------------

cat > "$index_tmp" <<EOF
<!DOCTYPE html>
<html lang="$site_language">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>$(printf '%s' "$site_title" | escape_html)</title>
<link rel="alternate" type="application/rss+xml" title="$(printf '%s' "$site_title" | escape_html)" href="$rss_file">
$( [[ -f style.css ]] && echo '<link rel="stylesheet" href="style.css">' )
<!-- Generated: $generated -->
</head>
<body>
EOF

# Optional page header
[[ -f head.html ]] && cat head.html >> "$index_tmp"

# Feed items
cat "$items_html" >> "$index_tmp"

# Optional page footer
[[ -f foot.html ]] && cat foot.html >> "$index_tmp"

cat >> "$index_tmp" <<EOF
</body>
</html>
EOF

# ----------------------------------------------------------------------
# Build RSS
# ----------------------------------------------------------------------

cat > "$rss_tmp" <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>$(printf '%s' "$site_title" | escape_html)</title>
<description>$(printf '%s' "$site_description" | escape_html)</description>
<link>$url_base</link>
<language>$site_language</language>
<lastBuildDate>$generated</lastBuildDate>
<atom:link href="$url_base/$rss_file" rel="self" type="application/rss+xml" />
EOF

cat "$items_rss" >> "$rss_tmp"

cat >> "$rss_tmp" <<EOF
</channel>
</rss>
EOF

# ----------------------------------------------------------------------
# Install generated files
# ----------------------------------------------------------------------

chmod 644 "$index_tmp" "$rss_tmp"

mv "$index_tmp" "$html_file"
mv "$rss_tmp" "$rss_file"

echo "Done"
