<script setup>
    import { computed } from 'vue';
    import AppAvatar from '@/components/AppAvatar.vue';

    const props = defineProps({
        approvals: {
            type: Array,
            default: () => [],
        },
        isCreateMode: {
            type: Boolean,
            default: false,
        },
        approvalMode: {
            type: String,
            default: 'Required',
        },
        contentStatus: {
            type: String,
            default: 'Draft',
        },
        isSubmittingDecision: {
            type: Boolean,
            default: false,
        },
    });

    const emit = defineEmits(['submit-decision']);

    const isMultiLevelApproval = computed(() => props.approvalMode === 'Multi-level');
    const isApprovalDisabled = computed(() => props.approvalMode === 'None');
    const sortedApprovals = computed(() =>
        [...props.approvals].sort((left, right) => {
            const leftOrder = left.workflowStepSortOrder ?? Number.MAX_SAFE_INTEGER;
            const rightOrder = right.workflowStepSortOrder ?? Number.MAX_SAFE_INTEGER;

            if (left.workflowInstanceId || right.workflowInstanceId) {
                return leftOrder - rightOrder;
            }

            return new Date(left.sentAt ?? 0).getTime() - new Date(right.sentAt ?? 0).getTime();
        })
    );
    const currentPendingApprovalId = computed(() =>
        sortedApprovals.value.find(approval => approval.state === 'Pending')?.id ?? null
    );
    const lifecycleRanks = {
        Draft: 0,
        'In production': 1,
        'In approval': 2,
        Approved: 3,
        Scheduled: 4,
        Published: 5,
    };
    const currentLifecycleRank = computed(() => lifecycleRanks[props.contentStatus] ?? 0);
    const hasApprovalSteps = computed(() => sortedApprovals.value.length > 0);
    const railSteps = computed(() => [
        productionStep(),
        ...approvalSteps(),
        publicationStep(),
    ]);

    function submitDecision(approvalId) {
        emit('submit-decision', approvalId, {
            decision: 'Approved',
            reviewerName: '',
            reviewerEmail: '',
        });
    }

    function formatApprovalStepMeta(approval) {
        if (!approval.workflowInstanceId) {
            return `${approval.stage} · ${approval.state}`;
        }

        const stepNumber = Number(approval.workflowStepSortOrder ?? 0) + 1;
        const requiredCount = approval.workflowStepRequiredApproverCount ?? 1;
        return `Step ${stepNumber} · ${approval.state} · ${requiredCount} required`;
    }

    function formatTarget(approval) {
        if (!approval.workflowStepTargetType) {
            return approval.reviewerEmail || 'Direct reviewer';
        }

        return `${approval.workflowStepTargetType}: ${approval.workflowStepTargetValue}`;
    }

    function formatDate(value) {
        return value ? new Date(value).toLocaleDateString() : 'No due date';
    }

    function formatDateTime(value) {
        return value ? new Date(value).toLocaleString() : '';
    }

    function stepStatus(approval) {
        if (approval.state === 'Approved') {
            return 'approved';
        }

        if (approval.id === currentPendingApprovalId.value) {
            return 'current';
        }

        return 'pending';
    }

    function canRecordDecision(approval) {
        if (approval.state !== 'Pending') {
            return false;
        }

        return !approval.workflowInstanceId || approval.id === currentPendingApprovalId.value;
    }

    function productionStep() {
        const status = currentLifecycleRank.value > lifecycleRanks['In production']
            ? 'approved'
            : 'current';

        return {
            id: 'production',
            kind: 'production',
            title: 'Production',
            state: props.contentStatus === 'Draft' ? 'Draft' : 'In production',
            status,
            meta: props.contentStatus === 'Draft'
                ? 'Content is being drafted.'
                : 'Content is being prepared before approval.',
            action: '',
        };
    }

    function approvalSteps() {
        if (hasApprovalSteps.value) {
            return sortedApprovals.value.map((approval, index) => ({
                id: approval.id,
                kind: 'approval',
                approval,
                title: approval.stage || approval.reviewerName || `Approval ${index + 1}`,
                state: approval.state,
                status: stepStatus(approval),
                meta: formatApprovalStepMeta(approval),
                action: canRecordDecision(approval) ? 'Click the circle to approve.' : '',
            }));
        }

        return [{
            id: 'approval',
            kind: 'approval-empty',
            title: 'Approval',
            state: approvalStateLabel(),
            status: approvalSyntheticStatus(),
            meta: approvalEmptyMeta(),
            action: '',
        }];
    }

    function publicationStep() {
        const status = props.contentStatus === 'Published'
            ? 'published'
            : props.contentStatus === 'Scheduled'
                ? 'scheduled'
                : 'pending';

        return {
            id: 'publication',
            kind: 'publication',
            title: props.contentStatus === 'Published' ? 'Published' : 'Publication',
            state: props.contentStatus === 'Published'
                ? 'Published'
                : props.contentStatus === 'Scheduled'
                    ? 'Scheduled'
                    : 'Pending',
            status,
            meta: props.contentStatus === 'Published'
                ? 'Content has been published.'
                : props.contentStatus === 'Scheduled'
                    ? 'Content is scheduled for publishing.'
                    : 'Content is not scheduled or published yet.',
            action: '',
        };
    }

    function approvalSyntheticStatus() {
        if (isApprovalDisabled.value || currentLifecycleRank.value > lifecycleRanks['In approval']) {
            return 'approved';
        }

        if (props.contentStatus === 'In approval') {
            return 'current';
        }

        return 'pending';
    }

    function approvalStateLabel() {
        if (isApprovalDisabled.value) {
            return 'Skipped';
        }

        if (currentLifecycleRank.value > lifecycleRanks['In approval']) {
            return 'Approved';
        }

        if (props.contentStatus === 'In approval') {
            return 'In approval';
        }

        return 'Pending';
    }

    function approvalEmptyMeta() {
        if (isApprovalDisabled.value) {
            return 'Approval is disabled for this workspace.';
        }

        if (isMultiLevelApproval.value) {
            return 'Move this content to In approval to start the configured workflow steps.';
        }

        return 'No approval activity yet.';
    }

    function stepLabel(step, index) {
        const action = step.action ? ` ${step.action}` : '';
        return `${step.title}. ${step.state}. ${step.meta}${action || ''}`.trim();
    }
</script>

<template>
    <aside
        class="approval-panel"
        aria-label="Approval workflow"
    >
        <div
            v-if="isCreateMode"
            class="approval-empty"
        >
            <span class="step-circle is-muted">1</span>
            <div class="step-popover">
                <strong>Approval</strong>
                <span>Save the content first to see workflow steps.</span>
            </div>
        </div>

        <ol
            v-else
            class="approval-stepper"
        >
            <li
                v-for="(step, index) in railSteps"
                :key="step.id"
                class="approval-step"
                :class="`is-${step.status}`"
            >
                <v-btn variant="text" :ripple="false"
                    class="step-circle"
                    type="button"
                    :disabled="step.kind !== 'approval' || !canRecordDecision(step.approval) || isSubmittingDecision"
                    :aria-label="stepLabel(step, index)"
                    @click="submitDecision(step.approval.id)"
                >
                    {{ index + 1 }}
                </v-btn>

                <div class="step-popover">
                    <div class="popover-heading">
                        <strong>{{ step.title }}</strong>
                        <span>{{ step.state }}</span>
                    </div>

                    <div class="popover-meta">
                        <span>Workflow</span>
                        <strong>{{ step.meta }}</strong>
                    </div>

                    <div class="popover-meta">
                        <template v-if="step.kind === 'approval'">
                        <span>Approver</span>
                            <strong>{{ step.approval.reviewerName || formatTarget(step.approval) }}</strong>
                            <small>{{ formatTarget(step.approval) }}</small>
                        </template>
                        <template v-else>
                            <span>Status</span>
                            <strong>{{ step.state }}</strong>
                        </template>
                    </div>

                    <div
                        v-if="step.kind === 'approval'"
                        class="popover-meta"
                    >
                        <span>Due</span>
                        <strong>{{ formatDate(step.approval.dueAt) }}</strong>
                    </div>

                    <div
                        v-if="step.kind === 'approval' && step.approval.decisions?.length"
                        class="decision-list"
                    >
                        <article
                            v-for="decision in step.approval.decisions"
                            :key="decision.id"
                            class="decision-row"
                        >
                            <AppAvatar
                                :name="decision.decidedByName"
                                :email="decision.decidedByEmail"
                                :src="decision.decidedByPortraitUrl"
                                size="sm"
                            />
                            <div>
                                <strong>{{ decision.decidedByName }}</strong>
                                <span>{{ decision.decision }} · {{ formatDateTime(decision.createdAt) }}</span>
                                <small v-if="decision.comment">{{ decision.comment }}</small>
                            </div>
                        </article>
                    </div>

                    <div
                        v-else
                        class="popover-meta"
                    >
                        <span>Action</span>
                        <strong>{{ step.action || 'No action available' }}</strong>
                    </div>
                </div>
            </li>
        </ol>
    </aside>
</template>

<style scoped>
@reference "@/assets/main.css";
    .approval-panel {
        @apply relative flex w-11 justify-center self-start;
    }

    .approval-empty strong,
    .popover-heading strong,
    .popover-meta strong,
    .decision-row strong {
        color: var(--app-color-on-surface);
    }

    .approval-empty span,
    .popover-heading span,
    .popover-meta span,
    .popover-meta small,
    .decision-row span,
    .decision-row small {
        @apply text-sm leading-6;
        color: var(--app-text-muted);
    }

    .approval-stepper,
    .decision-list {
        @apply flex flex-col gap-14;
    }

    .approval-step {
        @apply relative flex justify-center;
    }

    .approval-step:not(:last-child)::after {
        @apply absolute bottom-[-3.5rem] top-10 border-l-2 border-dashed;
        content: '';
        left: 50%;
        transform: translateX(-50%);
        border-color: rgba(23, 32, 51, 0.18);
    }

    .approval-empty {
        @apply relative flex justify-center;
    }

    .step-circle {
        @apply relative z-10 flex h-9 w-9 items-center justify-center rounded-full border text-xs font-black transition;
        background: var(--app-color-surface);
        border-color: rgba(23, 32, 51, 0.16);
        color: var(--app-text-muted);
    }

    button.step-circle:not(:disabled) {
        @apply cursor-pointer shadow-sm;
    }

    button.step-circle:not(:disabled):hover,
    button.step-circle:not(:disabled):focus-visible {
        transform: scale(1.06);
    }

    button.step-circle:disabled {
        cursor: default;
    }

    .step-circle.is-muted {
        background: var(--app-control-subtle);
    }

    .approval-step.is-approved .step-circle {
        background: var(--app-color-on-tertiary);
        border-color: var(--app-color-on-tertiary);
        color: var(--app-color-on-primary);
    }

    .approval-step.is-scheduled .step-circle {
        background: #b45309;
        border-color: #b45309;
        color: var(--app-color-on-primary);
    }

    .approval-step.is-published .step-circle {
        background: #7c3aed;
        border-color: #7c3aed;
        color: var(--app-color-on-primary);
    }

    .approval-step.is-current .step-circle {
        background: var(--app-color-on-surface);
        border-color: var(--app-color-on-surface);
        color: var(--app-color-on-primary);
    }

    .step-popover {
        @apply pointer-events-none absolute left-[calc(100%+0.75rem)] top-0 z-20 flex w-[18rem] translate-y-2 flex-col gap-3 rounded-[1rem] border p-4 opacity-0 shadow-xl transition;
        background: #ffffff;
        border-color: var(--app-border-subtle);
    }

    .approval-step:hover .step-popover,
    .approval-step:focus-within .step-popover,
    .approval-empty:hover .step-popover {
        @apply pointer-events-auto translate-y-0 opacity-100;
    }

    .popover-heading {
        @apply flex items-center justify-between gap-3;
    }

    .popover-meta {
        @apply flex flex-col gap-1;
    }

    .decision-row {
        @apply flex items-start gap-3 rounded-[0.875rem] border p-3;
        background: #f8fafc;
        border-color: var(--app-border-subtle);
    }

    .decision-row div {
        @apply flex min-w-0 flex-col gap-1;
    }

    @media (max-width: 639px) {
        .step-popover {
            width: min(18rem, calc(100vw - 5rem));
        }
    }

</style>
