<script>
    import { onMount }                from 'svelte';
    import { useTinyRouter }          from 'svelte-tiny-router';
    import { api, drop, get, patch, post } from '../../urls.svelte.js';
    import { error, yikes }           from '../../warn.svelte';
    import { t }         from '../../translations.svelte.js';
    import { timetrack } from '../../user.svelte.js';
    import { display }   from '../../time.svelte.js';
    import { now }       from '../../time.svelte';

    import TimeEditor from '../../Components/TimeRecordEditor.svelte';

    let detail = $state(null);
    let docLinks = $state(null);
    let router = useTinyRouter();

    let times = $state(null);
    let closed = $state(false);
    let tasks = {};
    let projects = {};
    let project_filter = $state(null);
    if (router.hasQueryParam('project')) project_filter = router.getQueryParam('project');
    let sortedTimes = $derived.by(() => Object.values(times).filter(match_prj_filter).map(time => ({
      ...time,
      start: display(time.start_time),
      end: display(time.end_time),
      end_date: display(time.end_time)?.substring(0,10)
    })).sort((b, a) => a.start_time - b.start_time));
    let selected = $state({});
    let ranges = {};
    let timeMap = $derived.by(calcYearMap);
    let selectionSum = $derived(sortedTimes.filter(time => selected[time.id]).map(time => time.duration).reduce((acc, a) => acc + a, 0));
    let users = null;

    $effect(() => {
        if (timetrack.running) {
            show(timetrack.running);
        } else {
            show(timetrack.stopped);
        }
    });

    async function addTime(task_id){
        let url  = api(`time/track_task/${task_id}`);
        let resp = await post(url,now()); // create new time or return time with assigned tasks
        if (resp.ok) {
            const track = await resp.json();
            if (timetrack.running){
                url  = api(`time/${timetrack.running.id}`);
                resp = await get(url);
                if (resp.ok){
                    let previous = await resp.json();
                    times[previous.id] = previous;
                }
            }
            timetrack.running = track;
        } else {
            error(resp);
        }
    }

    function calcYearMap(){
        console.log('calcYearMap called');
        let result = {
            months : {},
            years  : {}
        }
        let lastYear   = null;
        let lastMonth  = null;
        let yearCount  = 0;
        let monthCount = 0;
        let yearIndex  = 0;
        let monthIndex = 0;
        for (let idx in sortedTimes){
            const time  = sortedTimes[idx];
            const year  = time.start.substring(0,4);
            const month = time.start.substring(5,7);
            if (year != lastYear){
                lastYear = year;
                if (yearCount) result.years[yearIndex] = yearCount;
                yearCount = 0;
                yearIndex = idx;
            }
            yearCount +=1;
            if (month != lastMonth){
                lastMonth = month;
                if (monthCount) result.months[monthIndex] = monthCount;
                monthCount = 0;
                monthIndex = idx;
            }
            monthCount +=1;
        }
        if (yearCount)  result.years[yearIndex] = yearCount;
        if (monthCount) result.months[monthIndex] = monthCount;
        return result;
    }

    async function joinTimes(evt, id1, id2){
        evt.preventDefault();
        evt.stopPropagation();
        const url = api('time/join');
        const res = await post(url,`${id1}+${id2}`);
        if (res.ok){
            yikes();
            let json = await res.json();
            delete times[id1];
            delete times[id2];
            times[json.id] = json;
        } else {
            error(res);
        }
        return false;
    }



    async function loadTimes(){
        const url  = api('time');
        const resp = await post(url,{closed:closed});
        if (resp.ok){
            var json = await resp.json();
            times    = json.times;
            tasks    = json.tasks;
            projects = json.projects;
            docLinks = json.documents;
            users    = json.users;
        } else {
            error(resp);
        }
    }

    function match_prj_filter(time){
        if (!project_filter) return true;
        for (var tid of time.task_ids){
            if (tasks[tid] && project_filter == tasks[tid].project_id) return true;
        }
        return false;
    }

    function onAbort(){
        detail = null;
    }

    function onclick(e){
        e.preventDefault();
        let href = e.target.getAttribute('href');
        if (href) router.navigate(href);
        return false;
    }


    async function onDrop(time_id){
        const url = api(`time/${time_id}`);
        const res = await drop(url);
        if (res.ok){
            delete times[time_id];
            yikes();
        } else {
            error(res);
        }
    }

    async function multi_update(changeSet){
        changeSet.ids = Object.keys(selected).map(id => +id);
        const url = api('time');
        const res = await patch(url,changeSet);
        if (res.ok){
            yikes();
            var updated = await res.json();
            times = {...times, ...updated};
        } else error(res);
    }

    function openProject(pid){
        router.navigate(`/project/${pid}/view`);
    }

    function openTask(tid){
        router.navigate(`/task/${tid}/view`);
    }

    function reload(ev){
        loadTimes();
    }

    function show(track){
        if (times && track) times[track.id] = track;
    }


    function toggleRange(range){
        let affected = sortedTimes.filter(time => time.start.startsWith(range));
        if (ranges[range]){
            delete ranges[range];
            for (let time of affected){
                if (selected[time.id]) delete selected[time.id]
            }
        } else {
            for (let time of affected) selected[time.id] = true;
            ranges[range] = true;
        }
    }

    function toggleSelect(time_id){
        detail = null;
        if (selected[time_id]) {
            delete selected[time_id]
        } else selected[time_id] = true;
    }

    async function update(time){
        const url = api(`time/${time.id}`);
        const res = await fetch(url,{
            credentials:'include',
            method:'PATCH',
            body:JSON.stringify(time)
        });
        if (res.ok){
            let json = await res.json();
            let id = json.id;
            for (let key of Object.keys(json)) times[id][key] = json[key];
            detail = null;
            yikes();
            return true;
        } else {
            error(res);
            return false;
        }
    }

    onMount(loadTimes);
</script>

<svelte:head>
    <title>Umbrella – {t('timetracking')}</title>
</svelte:head>


<h1>{t('timetracking')}</h1>
{#if times}
{#if selectionSum}
<div class="timetracks sum">
    {t('sum_of_records')}: <span>{selectionSum.toFixed(3)}&nbsp;{t('hours')}</span>
    <button class="symbol" title={t('open')} onclick={e => multi_update({state:'Open'})} ></button>
    <button class="symbol" title={t('pending')} onclick={e => multi_update({state:'Pending'})} ></button>
    <button class="symbol" title={t('complete')} onclick={e => multi_update({state:'Complete'})} ></button>
</div>
{/if}
<div class="switch">
    <label>
        <input type="checkbox" bind:checked={closed} onchange={reload} />
        {t('show_closed')}
    </label>
</div>
<table class="timetracks">
    <thead>
        <tr>
            <th>{t('year')}</th>
            <th>{t('month')}</th>
            <th>{t('start')}<wbr>…<wbr>{t('end')}</th>
            <th>{t('duration')}</th>
            <th>{t('user')}</th>
            <th>{t('subject')}</th>
            <th>{t('projects')} / {t('tasks')}</th>
            <th>{t('state')}</th>
        </tr>
    </thead>
    <tbody>
        {#each sortedTimes as time,line}
        <tr class={selected[time.id]?'selected':''}>
            {#if timeMap.years[line]}
            <td class="year" rowspan={timeMap.years[line]} onclick={e => toggleRange(time.start.substring(0,4))} title={time.start.substring(0,4)} >
                {time.start.substring(0,4)}
            </td>
            {/if}
            {#if timeMap.months[line]}
            <td class="month" rowspan={timeMap.months[line]} onclick={e => toggleRange(time.start.substring(0,7))} title={time.start.substring(5,7)} >
                {time.start.substring(5,7)}
            </td>
            {/if}
            {#if detail == time.id}
            <td colspan="5">
                <TimeEditor record={time} {onAbort} {onDrop} onSet={update} />
            </td>
            {:else}
            <td class="start_end" onclick={e => toggleSelect(time.id)}>
                {time.start}{#if time.end_time}<wbr>…<wbr>{time.start.startsWith(time.end_date)?time.end.substring(11):time.end}{/if}
                {#if line>0 && (sortedTimes[line-1].user_id == time.user_id) && (Math.abs(sortedTimes[line-1].start_time - time.end_time)<100)}
                <button class="symbol join" title={t('join_objects',{objects:t('times')})} onclick={e => joinTimes(e, time.id, sortedTimes[line-1].id)} ></button>
                {/if}
            </td>
            <td class="duration" onclick={e => {detail = time.id}}>
                {#if time.duration}
                {time.duration.toFixed(3)}&nbsp;h
                {/if}
            </td>
            <td class="user" onclick={e => {detail = time.id}}>
                {users[time.user_id].name}
            </td>
            <td class="subject" onclick={e => {detail = time.id}}>
                {time.subject}
            </td>
            <td class="tasks">
            <ul>
                {#each time.task_ids as tid}
                {#if tasks[tid]}
                <li>
                    {#if tasks[tid] && projects[tasks[tid].project_id]}
                    <a href="/project/{tasks[tid].project_id}/view" {onclick}>{projects[tasks[tid].project_id].name}</a> /
                    {/if}
                    <a href="/task/{tid}/view" {onclick}>{tasks[tid].name}</a>
                    <button class="symbol" title={t('timetracking')} onclick={e => addTime(tid)}></button>
                </li>
                {/if}
                {/each}
            </ul>
            </td>
            <td class="state" onclick={e => {detail = time.id}}>
                {t("state_"+time.state.name.toLowerCase())}
                {#if time.state.name.toLowerCase() == 'pending' && docLinks[time.id]}
                <ul>
                    {#each Object.entries(docLinks[time.id]) as [a,b]}
                    <li>
                        <a href="/document/{a}/view" {onclick}>{b}</a>
                    </li>
                    {/each}
                </ul>
                {/if}
            </td>
            {/if}
        </tr>
        {/each}
    </tbody>
</table>
{/if}
