
___x_cmd_ccal_ls(){
    local mode=auto
    while [ $# -gt 0 ]; do
        case "$1" in
            -h|--help)          ___x_cmd help -m ccal ls "$@"; return 0 ;;
            --tsv|--csv|--tty|--yml|--auto)
                                    mode="${1#--}" ;;
            *)                      break ;;
        esac
        shift
    done

    # Auto-detect mode for ls
    if [ "$mode" = auto ]; then
        if ___x_cmd_is_stdout2tty; then
            mode=tty
        else
            mode=tsv
        fi
    fi

    local input="${1:-today}"

    ___x_cmd_ccal_lunar_prepare || return $?
    ___x_cmd_ccal_lunar_prepare_index || return $?

    case "$input" in
        t|today)
            # Default: show current month
            input="$(___x_cmd_cmds date +%Y-%m)"
            ___x_cmd_ccal_ls___month "$input" "$mode"
            ;;
        *-*-*)
            # Specific date -> show info-like for that day
            if [ "$mode" = tty ]; then
                # TTY mode: show single day in table format (not full month calendar)
                ___x_cmd_ccal_ls___day "$input" tty
            else
                ___x_cmd_ccal_info "$input" "$mode"
            fi
            ;;
        *-*)
            ___x_cmd_ccal_ls___month "$input" "$mode"
            ;;
        *)
            # x ccal ls 2026 -> show all 12 months of 2026
            ___x_cmd_ccal_ls___year_months "$input" "$mode"
            ;;
    esac
}

___x_cmd_ccal_around(){
    local mode=auto
    while [ $# -gt 0 ]; do
        case "$1" in
            -h|--help)          ___x_cmd help -m ccal around "$@"; return 0 ;;
            --tsv|--csv|--tty|--yml|--auto)
                                    mode="${1#--}" ;;
            *)                      break ;;
        esac
        shift
    done

    # Auto-detect mode for ls
    if [ "$mode" = auto ]; then
        if ___x_cmd_is_stdout2tty; then
            mode=tty
        else
            mode=tsv
        fi
    fi

    local input="${1:-today}"

    ___x_cmd_ccal_lunar_prepare || return $?
    ___x_cmd_ccal_lunar_prepare_index || return $?

    case "$input" in
        t|today)
            input="$(___x_cmd_cmds date +%Y-%m-%d)"
            ___x_cmd_ccal_ls___around "$input" "$mode"
            ;;
        *-*-*)
            ___x_cmd_ccal_ls___around "$input" "$mode"
            ;;
        *)
            ___x_cmd_ccal_ls___around "$input" "$mode"
            ;;
    esac
}

___x_cmd_ccal_ls___around(){
    local ymd="$1"
    local mode="${2:-tsv}"

    local y="${ymd%%-*}"
    local m="${ymd#*-}"; m="${m%-*}"
    local d="${ymd##*-}"

    m="${m#0}"
    d="${d#0}"

    # Pad day and month to 2 digits
    [ "$m" -lt 10 ] && m="0$m"
    [ "$d" -lt 10 ] && d="0$d"
    ymd="${y}-${m}-${d}"

    if [ "$y" -lt 100 ] && [ "$y" -ge 0 ]; then
        y="$(($y+2000))"
        ymd="$y-${m}-${d}"
    fi

    if [ "$y" -lt 1900 ] || [ "$y" -gt 2099 ]; then
        ccal:error "Invalid year -> $y"
        return 1
    fi

    # around shows ±7 days - raw TSV first, then format per mode
    ___x_cmd_ccal_ls___day_data "$ymd" "$y" "$m" | \
    ___x_cmd_cmds awk -F'\t' -v "mode=$mode" '
    function output_tsv() {
        printf "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", \
            $1, $2, $4, $5, ($7=="无"?"-":$7), $10, $12, $13, ($9==""?"-":$9)
    }
    function output_csv() {
        gsub(/"/, "\"\"", $12)
        gsub(/"/, "\"\"", $13)
        printf "\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"\n", \
            $1, $2, $4, $5, ($7=="无"?"-":$7), $10, $12, $13, ($9==""?"-":$9)
    }
    function output_yml() {
        printf "- date: %s\n", $1
        printf "  lunar_date: %s\n", $2
        printf "  jianchu: %s\n", $4
        printf "  weekday: %s\n", $5
        printf "  jieqi: %s\n", ($7=="无"?"-":$7)
        printf "  xiuxi: %s\n", ($10==""?"无":$10)
        printf "  yi: %s\n", $12
        printf "  ji: %s\n", $13
        printf "  holiday: %s\n", ($9==""?"无":$9)
    }
    function output_tty() {
        lunar = $2
        if ($5 != "") lunar = lunar " (闰" $5 ")"
        xiuxi = $10; if (xiuxi == "") xiuxi = "-"
        yi = $12; if (yi == "") yi = "-"
        ji = $13; if (ji == "") ji = "-"
        holiday = $9; if (holiday == "") holiday = "-"
        gsub(/[ \t]+/, " ", yi)
        gsub(/[ \t]+/, " ", ji)
        if (length(yi) > 20) yi = substr(yi, 1, 17) "..."
        if (length(ji) > 20) ji = substr(ji, 1, 17) "..."
        if (length(holiday) > 18) holiday = substr(holiday, 1, 15) "..."
        style = "\033[0m"
        if (xiuxi == "休") style = "\033[31m"
        else if (xiuxi == "工") style = "\033[36m"
        printf "%s%-12s %-10s %-6s %-10s %-4s %-20s %-20s %-18s\033[0m\n", \
            style, $1, lunar, $4, ($7=="无"?"-":$7), xiuxi, yi, ji, holiday
    }
    BEGIN { if (mode == "tty") printf "%-12s %-10s %-6s %-10s %-4s %-20s %-20s %-18s\n", "Date", "Lunar", "Week", "Jieqi", "Xiuxi", "Yi", "Ji", "Holiday" }
    {
        if (mode == "tsv") output_tsv()
        else if (mode == "csv") output_csv()
        else if (mode == "yml") output_yml()
        else if (mode == "tty") output_tty()
    }
    '
}

___x_cmd_ccal_ls___year(){
    local year="$1"
    local mode="${2:-tsv}"

    if [ "$year" -lt 100 ] && [ "$year" -ge 0 ]; then
        year="$(($year+2000))"
    fi

    if [ "$year" -lt 1900 ] || [ "$year" -gt 2099 ]; then
        ccal:error "Invalid year -> $year"
        return 1
    fi

    local cache_folder="${___X_CMD_CCAL_LUNAR_INDEX_FOLDER:-$___X_CMD_CCAL_DATA/$___X_CMD_CCAL_DATA_VERSION/cache}"

    case "$mode" in
        tsv)
            ___x_cmd_cmds awk \
                -v "year=$year" \
                -f "$___X_CMD_ROOT_MOD/ccal/lib/awk/lunar.awk" \
                -f "$___X_CMD_ROOT_MOD/ccal/lib/awk/fzy_ls.awk" \
                < "$cache_folder/year.tsv"
            ;;
        csv)
            ___x_cmd_cmds awk \
                -v "year=$year" \
                -f "$___X_CMD_ROOT_MOD/ccal/lib/awk/lunar.awk" \
                -f "$___X_CMD_ROOT_MOD/ccal/lib/awk/fzy_ls.awk" \
                < "$cache_folder/year.tsv" | \
            ___x_cmd tsv tocsv
            ;;
        yml)
            ___x_cmd_cmds awk \
                -v "year=$year" \
                -f "$___X_CMD_ROOT_MOD/ccal/lib/awk/lunar.awk" \
                -f "$___X_CMD_ROOT_MOD/ccal/lib/awk/fzy_ls.awk" \
                < "$cache_folder/year.tsv" | \
            ___x_cmd_cmds awk -F'\t' '
            {
                printf "- year: %s\n", $1
                printf "  xuanyuan: %s\n", $2
                printf "  shengxiao: %s\n", $3
                printf "  leap_months: %s\n", $4
                printf "  leap_month_list: %s\n", $5
                printf "  chunjie: %s\n", $6
                printf "  qingming: %s\n", $7
                printf "  duanwu: %s\n", $8
                printf "  zhongqiu: %s\n", $9
            }'
            ;;
        tty|*)
            ___x_cmd_cmds awk \
                -v "year=$year" \
                -f "$___X_CMD_ROOT_MOD/ccal/lib/awk/lunar.awk" \
                -f "$___X_CMD_ROOT_MOD/ccal/lib/awk/fzy_ls.awk" \
                < "$cache_folder/year.tsv"
            ;;
    esac
}

# x ccal ls year <year> - show all 12 months of the given year
___x_cmd_ccal_ls___year_months(){
    local year="$1"
    local mode="${2:-tsv}"

    if [ "$year" -lt 100 ] && [ "$year" -ge 0 ]; then
        year="$(($year+2000))"
    fi

    if [ "$year" -lt 1900 ] || [ "$year" -gt 2099 ]; then
        ccal:error "Invalid year -> $year"
        return 1
    fi

    # Iterate through all 12 months
    local m
    for m in $(seq 1 12); do
        ___x_cmd_ccal_ls___month "${year}-${m}" "$mode"
    done
}

___x_cmd_ccal_ls___month(){
    local ym="$1"
    local mode="${2:-tsv}"

    local y="${ym%%-*}"
    local m="${ym#*-}"
    m="${m#0}"

    if [ "$y" -lt 100 ] && [ "$y" -ge 0 ]; then
        y="$(($y+2000))"
    fi

    if [ "$y" -lt 1900 ] || [ "$y" -gt 2099 ]; then
        ccal:error "Invalid year -> $y"
        return 1
    fi

    if [ "$m" -lt 1 ] || [ "$m" -gt 12 ]; then
        ccal:error "Invalid month -> $m"
        return 1
    fi

    # Month view now shows day-level data
    local first_day="${y}-${m#0}-01"
    ___x_cmd_ccal_ls___month_daydata "$first_day" "$y" "$m" "$mode"
}

___x_cmd_ccal_ls___month_daydata(){
    local first_ymd="$1"
    local y="$2"
    local m="$3"
    local mode="${4:-tsv}"

    local pm py nm ny
    if [ "$m" -eq 1 ]; then
        pm=12; py=$((y-1))
    else
        pm=$((m-1)); py=$y
    fi

    if [ "$m" -eq 12 ]; then
        nm=1; ny=$((y+1))
    else
        nm=$((m+1)); ny=$y
    fi

    {
        ___x_cmd_ccal_lunar_cat "$py" "$pm" --tsv 2>/dev/null
        ___x_cmd_ccal_lunar_cat "$y" "$m" --tsv 2>/dev/null
        ___x_cmd_ccal_lunar_cat "$ny" "$nm" --tsv 2>/dev/null
    } | ___x_cmd_cmds awk -v "year=$y" -v "month=$m" -F '\t' '
        function date2int(s, a) {
            split(s, a, "-")
            return a[1]*10000 + a[2]*100 + a[3]
        }
        BEGIN {
            start = year * 100 + month
            end = start + 1
        }
        NR==1 { next }
        {
            di = date2int($1)
            if (di >= start * 100 + 1 && di < end * 100 + 1) print
        }
    ' | ___x_cmd_cmds awk -F'\t' -v "mode=$mode" '
    function output_tsv() {
        printf "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", \
            $1, $2, $4, $5, ($7=="无"?"-":$7), $10, $12, $13, ($9==""?"-":$9)
    }
    function output_csv() {
        gsub(/"/, "\"\"", $12)
        gsub(/"/, "\"\"", $13)
        printf "\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"\n", \
            $1, $2, $4, $5, ($7=="无"?"-":$7), $10, $12, $13, ($9==""?"-":$9)
    }
    function output_yml() {
        printf "- date: %s\n", $1
        printf "  lunar_date: %s\n", $2
        printf "  jianchu: %s\n", $4
        printf "  weekday: %s\n", $5
        printf "  jieqi: %s\n", ($7=="无"?"-":$7)
        printf "  xiuxi: %s\n", ($10==""?"无":$10)
        printf "  yi: %s\n", $12
        printf "  ji: %s\n", $13
        printf "  holiday: %s\n", ($9==""?"无":$9)
    }
    function output_tty() {
        lunar = $2
        if ($5 != "") lunar = lunar " (闰" $5 ")"
        xiuxi = $10; if (xiuxi == "") xiuxi = "-"
        yi = $12; if (yi == "") yi = "-"
        ji = $13; if (ji == "") ji = "-"
        holiday = $9; if (holiday == "") holiday = "-"
        gsub(/[ \t]+/, " ", yi)
        gsub(/[ \t]+/, " ", ji)
        if (length(yi) > 20) yi = substr(yi, 1, 17) "..."
        if (length(ji) > 20) ji = substr(ji, 1, 17) "..."
        if (length(holiday) > 18) holiday = substr(holiday, 1, 15) "..."
        style = "\033[0m"
        if (xiuxi == "休") style = "\033[31m"
        else if (xiuxi == "工") style = "\033[36m"
        printf "%s%-12s %-10s %-6s %-10s %-4s %-20s %-20s %-18s\033[0m\n", \
            style, $1, lunar, $4, ($7=="无"?"-":$7), xiuxi, yi, ji, holiday
    }
    BEGIN { if (mode == "tty") printf "%-12s %-10s %-6s %-10s %-4s %-20s %-20s %-18s\n", "Date", "Lunar", "Week", "Jieqi", "Xiuxi", "Yi", "Ji", "Holiday" }
    {
        if (mode == "tsv") output_tsv()
        else if (mode == "csv") output_csv()
        else if (mode == "yml") output_yml()
        else if (mode == "tty") output_tty()
    }
    '
}

___x_cmd_ccal_ls___day(){
    local ymd="$1"
    local mode="${2:-tsv}"

    local y="${ymd%%-*}"
    local m="${ymd#*-}"; m="${m%-*}"
    local d="${ymd##*-}"

    m="${m#0}"
    d="${d#0}"

    # Pad day and month to 2 digits
    [ "$m" -lt 10 ] && m="0$m"
    [ "$d" -lt 10 ] && d="0$d"
    ymd="${y}-${m}-${d}"

    if [ "$y" -lt 100 ] && [ "$y" -ge 0 ]; then
        y="$(($y+2000))"
        ymd="$y-${m}-${d}"
    fi

    if [ "$y" -lt 1900 ] || [ "$y" -gt 2099 ]; then
        ccal:error "Invalid year -> $y"
        return 1
    fi

    case "$mode" in
        tsv)
            ___x_cmd_ccal_ls___day_data "$ymd" "$y" "$m" | \
            ___x_cmd_cmds awk -F'\t' '
            {
                printf "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", \
                    $1, $2, $4, $5, ($7=="无"?"-":$7), $10, $12, $13, ($9==""?"-":$9)
            }'
            ;;
        csv)
            ___x_cmd_ccal_ls___day_data "$ymd" "$y" "$m" | \
            ___x_cmd_cmds awk -F'\t' '
            {
                gsub(/"/, "\"\"", $12)
                gsub(/"/, "\"\"", $13)
                printf "\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"\n", \
                    $1, $2, $4, $5, ($7=="无"?"-":$7), $10, $12, $13, ($9==""?"-":$9)
            }'
            ;;
        yml)
            ___x_cmd_ccal_ls___day_data "$ymd" "$y" "$m" | \
            ___x_cmd_cmds awk -F'\t' '
            {
                printf "- date: %s\n", $1
                printf "  lunar_date: %s\n", $2
                printf "  jianchu: %s\n", $4
                printf "  weekday: %s\n", $5
                printf "  jieqi: %s\n", ($7=="无"?"-":$7)
                printf "  xiuxi: %s\n", ($10==""?"无":$10)
                printf "  yi: %s\n", $12
                printf "  ji: %s\n", $13
                printf "  holiday: %s\n", ($9==""?"无":$9)
            }'
            ;;
        tty|*)
            printf "%-12s %-10s %-6s %-10s %-4s %-20s %-20s %-18s\n" \
                "Date" "Lunar" "Week" "Jieqi" "Xiuxi" "Yi" "Ji" "Holiday"

            ___x_cmd_ccal_ls___day_data "$ymd" "$y" "$m" | \
            ___x_cmd_cmds awk -F'\t' -v "target=$ymd" '
            $1 == target {
                lunar = $2
                if ($5 != "") lunar = lunar " (闰" $5 ")"
                xiuxi = $10; if (xiuxi == "") xiuxi = "-"
                yi = $12; if (yi == "") yi = "-"
                ji = $13; if (ji == "") ji = "-"
                holiday = $9; if (holiday == "") holiday = "-"
                gsub(/[ \t]+/, " ", yi)
                gsub(/[ \t]+/, " ", ji)
                if (length(yi) > 20) yi = substr(yi, 1, 17) "..."
                if (length(ji) > 20) ji = substr(ji, 1, 17) "..."
                if (length(holiday) > 18) holiday = substr(holiday, 1, 15) "..."
                style = "\033[0m"
                if (xiuxi == "休") style = "\033[31m"
                else if (xiuxi == "工") style = "\033[36m"
                printf "%s%-12s %-10s %-6s %-10s %-4s %-20s %-20s %-18s\033[0m\n", \
                    style, $1, lunar, $4, ($7=="无"?"-":$7), xiuxi, yi, ji, holiday
            }'
            ;;
    esac
}

___x_cmd_ccal_ls___day_data(){
    local ymd="$1"
    local y="$2"
    local m="$3"

    # Parse the target date components
    local d="${ymd##*-}"
    local m_without_d="${ymd%-$d}"
    local m_num="${m_without_d#*-}"
    m_num="${m_num#0}"
    d="${d#0}"

    # Read 3 months of data to cover ±7 days (spans at most 1 month)
    # prev-month, current, next-month
    local pm py nm ny
    if [ "$m_num" -eq 1 ]; then
        pm=12; py=$((y - 1))
    else
        pm=$((m_num - 1)); py=$y
    fi
    if [ "$m_num" -eq 12 ]; then
        nm=1; ny=$((y + 1))
    else
        nm=$((m_num + 1)); ny=$y
    fi

    {
        ___x_cmd_ccal_lunar_cat "$py" "$pm" --tsv 2>/dev/null
        ___x_cmd_ccal_lunar_cat "$y" "$m_num" --tsv 2>/dev/null
        ___x_cmd_ccal_lunar_cat "$ny" "$nm" --tsv 2>/dev/null
    } | ___x_cmd_cmds awk -v "y=$y" -v "m=$m_num" -v "d=$d" -F '\t' '
        function date2int(s, a) {
            split(s, a, "-")
            return a[1]*10000 + a[2]*100 + a[3]
        }
        # Days in month - proper lookup
        function daysInMonth(y, m) {
            if (m == 2) return (y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) ? 29 : 28
            if (m == 4 || m == 6 || m == 9 || m == 11) return 30
            return 31
        }
        # Add days to date
        function addDays(y, m, d, n, ny, nm, nd) {
            nd = d + n
            nm = m
            ny = y
            while (nd > daysInMonth(ny, nm)) {
                nd -= daysInMonth(ny, nm)
                nm++
                if (nm > 12) { ny++; nm = 1 }
            }
            while (nd < 1) {
                nm--
                if (nm < 1) { ny--; nm = 12 }
                nd += daysInMonth(ny, nm)
            }
            return sprintf("%04d-%02d-%02d", ny, nm, nd)
        }
        NR==1 { next }
        {
            di = date2int($1)
            start = addDays(y, m, d, -7)
            end = addDays(y, m, d, 7)
            rsi = date2int(start)
            rei = date2int(end)
            if (di >= rsi && di <= rei) print
        }
    '
}
