<script>
    import {getContext} from "svelte";
    import {uniqBy} from "lodash";
    import PreviewCardInline from "../PreviewCardInline.svelte";
    import {getErrorMessage} from "./errorMessage";
    import {sortByField} from "../../edges/sortEdges";
    import ReferenceInlineButtons from "./ReferenceInlineButtons.svelte";
    import {flip} from "svelte/animate";
    import {quintOut} from 'svelte/easing';

    const channel = getContext("channel");
    export let field;
    export let record;
    export let graph;
    export let validationErrors;

    $: errorMessage = getErrorMessage(validationErrors, field.name);

    $: references = graph.edges
        .filter((edge) => edge.field === field.name)
        .map((edge) => {
            return graph.records.find((increc) => increc.id == edge.target && record.id == edge.source);
        }).filter((rec) => (rec?.id ? true : false)) ?? [];


    let collections = channel.schemas.filter((aschema) =>
        field.collections.includes(aschema.name)
    );

    function handleInlinesaved(e) {
        const updatedRecord = e.detail.records[0];
        graph.edges = graph.edges.map((child) => {
            if (child.source === updatedRecord.id) {
                return updatedRecord;
            }
            return child;
        });
    }

    function removeReference(e) {
        e.preventDefault();
        graph.edges = graph.edges.filter(
            (edge) => !(edge.target === e.detail && edge.field === field.name)
        );
    }

    function trashReference(e) {
        e.preventDefault();
        graph.edges = graph.edges.map((edge) => {
            if (edge.target === e.detail && edge.field === field.name) {
                edge._isTrashed = true;
            }
            return edge;
        });
    }

    function undoRemoveReference(e) {
        e.preventDefault();
        graph.edges = graph.edges.map((edge) => {
            if (edge.target === e.detail && edge.field === field.name) {
                delete edge._isTrashed;
            }
            return edge;
        });
    }

    function insert(e) {
        e.preventDefault();

        const recordsToInsert = e.detail.records;
        const insertAfter = e.detail.after ?? null;
        const action = e.detail.action;
        let newEdges = recordsToInsert.map((r) => {
            return {
                target: r.id,
                source: record.id,
                sourceSchema: record.schema,
                targetSchema: r.schema,
                field: field.name,
                rank: ""
            };
        });

        let replacedEdges = graph.edges;
        if (action === "replace") {
            replacedEdges = replacedEdges.filter((edge) => edge.field !== field.name);
        }
        graph.records = uniqBy([...graph.records, ...recordsToInsert], (r) => r.id);
        graph.edges = uniqBy([...replacedEdges, ...newEdges], (edge) => edge.target + edge.field);

        if (!insertAfter) {
            graph.edges = uniqBy(
                [...newEdges, ...replacedEdges],
                (edge) => edge.target + edge.field
            );
        } else {
            let isAfter = false;
            let beforeAfter = replacedEdges.reduce(
                (c, edge) => {
                    if (isAfter) {
                        c.after.push(edge);
                    } else {
                        c.before.push(edge);
                    }

                    if (isAfter === false && edge.target === insertAfter) {
                        isAfter = true;
                    }
                    return c;
                },
                {before: [], after: []}
            );

            graph.edges = uniqBy(
                [...beforeAfter.before, ...newEdges, ...beforeAfter.after],
                (e) => e.target + e.field
            );
        }
    }

    function move(e, from, to) {
        graph.edges = sortByField(from, to, graph.edges, field.name);
    }
</script>

{#if errorMessage}
    <div class="invalid-feedback d-block mb-3">
        {errorMessage}
    </div>
{/if}
<div class="inline-card-wrapper">
    <ReferenceInlineButtons
        {field}
        recordId={null}
        schemas={collections}
        on:insert={insert}
        on:save={insert}
    />
</div>
{#if references.length > 0}
    {#each references as reference, i (reference.id)}
        <div class="inline-card-wrapper" animate:flip="{{delay: 250, duration: 250, easing: quintOut}}">
            <PreviewCardInline
                isFirst={i === 0}
                isLast={i + 1 === references.length}
                bind:record={reference}
                toDelete={graph.edges.find(
                    (edge) =>
                        edge.field === field.name && edge.target === reference.id
                )._isTrashed}
                on:inlinesaved={handleInlinesaved}
                on:moveup={(e) => move(e, i, i - 1)}
                on:movedn={(e) => move(e, i, i + 1)}
                on:remove={removeReference}
                on:undoremove={undoRemoveReference}
                on:trash={trashReference}
            />
            <ReferenceInlineButtons
                {field}
                recordId={reference.id}
                schemas={collections}
                on:insert={insert}
                on:save={insert}
            />
        </div>
    {/each}
{/if}
