<!-- Base component for schedules -->
<script setup lang="ts">
import Checkboxes from '../form/Checkboxes.vue';
import TimeSelect from '../form/TimeSelect.vue';
import Select from '../form/Select.vue';
import Toggle from '../form/Toggle.vue';
import Badge from '../base/Badge.vue';
import Popup from '../layout/Popup.vue';
import PopupTextarea from '../layout/PopupTextarea.vue';
import IconWarning from '../icons/IconWarning.vue';
import useGetTimezones from '~src/admin/composables/useGetTimezones';
import { computed, inject, ref, watch, watchEffect } from 'vue';
import { AdvancedScheduleType, AppConfigType, OptionType, ScheduleType } from '~src/admin/types';
import { useRouter } from 'vue-router';
import Message from '../base/Message.vue';
import Button from '../base/Button.vue';
import IconPlus from '../icons/IconPlus.vue';
import { useGettext } from 'vue3-gettext';
import { useTokensStore } from '~src/admin/stores/useTokensStore';
import DateRangeSelect from '../form/DateRangeSelect.vue';

// Translations
const { $gettext } = useGettext();

// Get plugin config
const config: AppConfigType = inject('pluginConfig');

// Props
const { schedule, isPreview = false } = defineProps<{
    schedule: ScheduleType;
    isPreview?: boolean;
}>();

// Emits
const emit = defineEmits<{
    updateSchedule: [schedule: ScheduleType];
	articlesLeftUpdate: [articlesLeft: number];
}>();

// Router
const router = useRouter();

// Popup control
const upgradePopup = ref<InstanceType<typeof Popup>>();

// Get current token count
const { usedTokens, totalTokens, refreshTokens } = useTokensStore();

// Weekday options
const weekdayOptions = ref<OptionType[]>([
    { label: $gettext('Monday'), value: '1' },
    { label: $gettext('Tuesday'), value: '2' },
    { label: $gettext('Wednesday'), value: '3' },
    { label: $gettext('Thursday'), value: '4' },
    { label: $gettext('Friday'), value: '5' },
    { label: $gettext('Saturday'), value: '6' },
    { label: $gettext('Sunday'), value: '0' },
]);

// Account type
const isAccountFree = inject<boolean>('isAccountFree');

// Account expired
const isAccountExpired = inject<boolean>('isAccountExpired');

// Get all time zones for select
const timeZones = useGetTimezones();
const userTimeZone = config.wordpress.timezone || Intl.DateTimeFormat().resolvedOptions().timeZone;

// Store values from inputs
const selectedTime = ref(schedule.time || '10:00');
const selectedDays = ref<string | string[]>(null);
const selectedTimeZone = ref<string>(userTimeZone);
const activityDateEnabled = ref<boolean>(schedule.activity_date_enabled ?? false);
const selectedActivityDate = ref<string[]>(schedule.activity_date ?? []);

// Set selected days default
if (isAccountFree && schedule.days) {
    selectedDays.value = schedule.days?.[0] ?? '1';
} else if (!isAccountFree && schedule.days) {
    selectedDays.value = schedule.days;
}

// Schedule type
const isAdvancedSchedule = ref(schedule.advSchedule ? true : false);

// Store all times for all days
const advancedTimes = ref<AdvancedScheduleType>(
    schedule.advSchedule ?? {
        '1': [],
        '2': [],
        '3': [],
        '4': [],
        '5': [],
        '6': [],
        '0': [],
    }
);

// Calculate usage percentage
const recentUsedArticles = usedTokens;
const totalArticles = totalTokens;

// Get initial used articles
const initialUsedArticles = ref(0);

const calculateInitialUsedArticles = () => {
    if (isAdvancedSchedule.value && advancedTimes.value) {
        // Advanced schedule
        initialUsedArticles.value = Object.values(advancedTimes.value).reduce((sum, arr) => sum + arr.length, 0);
    } else if (!isAdvancedSchedule.value) {
        // Basic schedule
        initialUsedArticles.value = selectedDays.value.length;
    }
};
calculateInitialUsedArticles();

// Keyword popups
const keywordPopup = ref<InstanceType<typeof PopupTextarea>>();

// Set the current keyword and its index for editing
const articleKeywords = ref<string[][][]>(schedule.articles_keywords ?? []);
const currentKeyword = ref<string>('');
const currentKeywordDayIndex = ref<number>(0);
const currentKeywordTimeIndex = ref<number>(0);

// Set keyword and index
const openKeywordPopup = (keyword: string[], dayIndex: number, timeIndex?: number) => {
    // Set the current keyword and indexes
    currentKeyword.value = keyword?.join(',') ?? '';
    currentKeywordDayIndex.value = dayIndex;
    if (timeIndex !== undefined) {
        currentKeywordTimeIndex.value = timeIndex;
    }

    // Open the popup
    keywordPopup.value.openPopup();
};

// Update selected keyword
const updateKeyword = () => {
    if (schedule.advSchedule) {
        articleKeywords.value[currentKeywordDayIndex.value][currentKeywordTimeIndex.value] =
            currentKeyword.value.split(',');
    } else {
        articleKeywords.value[currentKeywordDayIndex.value] = [currentKeyword.value.split(',')];
    }

    // Close the popup
    keywordPopup.value.closePopup();
};

// Update initial used articles on refresh
watch(
    () => refreshTokens.value,
    () => {
        calculateInitialUsedArticles();
    }
);

const usedArticles = computed(() => {
    // Sum existing articles and the potential new ones
    let currentSum = 0;

    if (isAdvancedSchedule.value && advancedTimes.value) {
        // Advanced schedule
        currentSum = Object.values(advancedTimes.value).reduce((sum, arr) => sum + arr.length, 0);
    } else if (!isAdvancedSchedule.value) {
        // Basic schedule
        currentSum = selectedDays.value.length;
    }

    // Calculate the sum
    let sum = recentUsedArticles.value + currentSum - initialUsedArticles.value;

    // If the sum is less than inital, don't change it
    if (sum < usedTokens.value) {
        sum = usedTokens.value;
    }

    return sum;
});

// Calculate current article usage
const articlesPercentage = computed(() => {
    return Math.round((usedArticles.value / totalArticles.value) * 100);
});

// Calculate articles left
const articlesLeft = computed(() => {
    let articlesLeft = totalArticles.value - usedArticles.value;

    // Prevent negative values
    if (articlesLeft < 0) {
        articlesLeft = 0;
    }

    return articlesLeft;
});

// Show correct color
const messageColor = ref('success');

watchEffect(() => {
    if (articlesPercentage.value < 50) {
        messageColor.value = 'success';
    } else if (articlesPercentage.value >= 50 && articlesPercentage.value < 75) {
        messageColor.value = 'warning';
    } else {
        messageColor.value = 'danger';
    }
});

// Remove time select
const removeTimeSelect = (day: string, index: number) => {
    // Remove the time select
    advancedTimes.value[day].splice(index, 1);

    // Remove the keyword for the selected time select
    articleKeywords.value[Number(day)][index] = [];

    // If the time select has no values deselect it
    if (advancedTimes.value[day].length === 0 && Array.isArray(selectedDays.value)) {
        const dayIndex = selectedDays.value.findIndex((d) => d === day);
        selectedDays.value.splice(dayIndex, 1);
    }
};

watch(selectedDays, (newSelectedDays, oldSelectedDays) => {
    if (!Array.isArray(oldSelectedDays)) return;

    // Get deselected day
    const removed = oldSelectedDays.filter((x) => !newSelectedDays.includes(x))[0];

    // Remove the keyword for the selected day
    if (removed) {
        articleKeywords.value[removed] = [];
    }

    // Remove all dates when deselecting a whole day
    if (!isAdvancedSchedule.value) return;

    // Remove all time selects
    if (removed && advancedTimes.value?.[removed]) {
        advancedTimes.value[removed] = [];
    }

    if (!Array.isArray(newSelectedDays)) return;

    // Check for new selected day
    const added = newSelectedDays.filter((x) => !oldSelectedDays.includes(x))[0];

    // Add a default hour to a day
    if (added && advancedTimes.value?.[added]) {
        advancedTimes.value[added].push('10:00');
        articleKeywords.value[added][0] = [];
    }
});

// Check if there are no empty days when changing the schedule type
watch(isAdvancedSchedule, () => {
    if (!isAdvancedSchedule.value) return;

    for (const day in advancedTimes.value) {
        // Check if day is selected and add defualt time if it's empty
        if (selectedDays.value.includes(day) && advancedTimes.value[day].length === 0) {
            advancedTimes.value[day].push('10:00');
        }
    }
});

// Emit the new schedule on each change
watch(
    [
        selectedTime,
        selectedDays,
        selectedTimeZone,
        isAdvancedSchedule,
        articleKeywords,
        activityDateEnabled,
        selectedActivityDate,
    ],
    () => {
        // Generate new weekdays based on the type
        const newWeekDays = Array.isArray(selectedDays.value) ? selectedDays.value : selectedDays.value.split('');

        const newSchedule: ScheduleType = {
            ...schedule,
            time: selectedTime.value,
            time_zone: selectedTimeZone.value,
            days: newWeekDays,
            advSchedule: isAdvancedSchedule.value ? advancedTimes.value : null,
            articles_keywords: articleKeywords.value,
            activity_date_enabled: activityDateEnabled.value,
            activity_date: selectedActivityDate.value,
        };

        emit('updateSchedule', newSchedule);
    },
    {
        // Emit on mounted in case no values are changed
        immediate: true,
    }
);

// Add a watcher for articlesLeft to emit its value when it changes
watch(
    usedArticles,
    () => {
		const newArticlesLeft = totalArticles.value - usedArticles.value;
        emit('articlesLeftUpdate', newArticlesLeft);
    },
    {
        immediate: true, // Emit on mount
    }
);
</script>

<template>
    <!-- Available articles left -->
    <div class="text-center flex flex-col items-center gap-4 mb-11">
        <Message
            :message="`${articlesLeft} ${$gettext('articles out of')} ${totalArticles} ${$gettext(
                'left to be scheduled for the week.'
            )}`"
            :type="messageColor"
            size="large"
        />

        <Message
            :message="
                $gettext(
                    'To generate an article for today, please schedule it at least 3 hours from the current time.'
                )
            "
            type="info"
            size="large"
            :show-icon="true"
        />
    </div>
    <!-- Available articles left -->

    <!-- Toggle -->
    <div
        class="flex flex-col md:flex-row gap-2.5 items-center justify-center mb-5"
        v-if="isPreview || !isAccountFree || !isAccountExpired"
    >
        <div class="cursor-pointer" @click="isAccountFree ? upgradePopup.openPopup() : null">
            <Toggle
                :class="(isAccountFree || isAccountExpired) && 'pointer-events-none'"
                :inactive-text="$gettext('Basic schedule')"
                :active-text="$gettext('Advanced schedule')"
                v-model="isAdvancedSchedule"
            />
        </div>

        <Badge class="max-md:self-end" type="warning" v-if="isAccountFree">{{ $gettext('PRO feature') }}</Badge>
    </div>
    <!-- Toggle -->

    <!-- Days of the week -->
    <div class="flex justify-center flex-wrap max-sm:max-w-[220px] max-sm:mx-auto gap-2.5">
        <!-- Checkbox -->
        <div
            class="max-sm:w-full sm:max-w-[140px] sm:flex-1"
            v-for="(option, dayIndex) in weekdayOptions"
            :key="dayIndex"
        >
            <Checkboxes
                :options="[option]"
                :name="`${schedule.id}-weekday-${dayIndex}`"
                type="border"
                size="large"
                :selection="isAccountFree ? 'single' : 'multiple'"
                v-model="selectedDays"
                :global-disabled="((isAccountFree && isPreview) || isAccountExpired) || articlesLeft <= 0"
            />

            <!-- Edit keywords -->
            <Button
                class="mt-1.5 w-full"
                type="secondary"
                :text="$gettext('Edit keywords')"
                size="small"
                :has-background="false"
                v-if="!isAdvancedSchedule && isPreview && schedule.days.includes(option.value)"
                @click.prevent="openKeywordPopup(articleKeywords[(dayIndex + 1) % 7][0], (dayIndex + 1) % 7)"
            />

            <!-- Time selects -->
            <div v-if="isAdvancedSchedule">
                <!-- Single time select -->
                <div
                    class="relative mt-1.5 flex flex-col gap-1.5"
                    v-for="(_, timeIndex) in advancedTimes[option.value]"
                    :key="timeIndex"
                >
                    <TimeSelect
                        size="small"
                        v-model="advancedTimes[option.value][timeIndex]"
                        :add-remove="true"
                        @remove-time-select="removeTimeSelect(option.value, timeIndex)"
                    />

                    <!-- Edit keywords -->
                    <Button
                        class="mt-0.5 w-full"
                        type="secondary"
                        :text="$gettext('Edit keywords')"
                        size="small"
                        :has-background="false"
                        v-if="isAdvancedSchedule && isPreview"
                        @click.prevent="
                            openKeywordPopup(
                                articleKeywords[(dayIndex + 1) % 7][timeIndex],
                                (dayIndex + 1) % 7,
                                timeIndex
                            )
                        "
                    />
                </div>

                <!-- Add time -->
                <Button
                    class="w-full mt-1.5 bg-white"
                    type="secondary"
                    :text="$gettext('Add time')"
                    size="small"
                    :has-background="false"
                    :icon-position="'left'"
                    :disabled="!selectedDays.includes(option.value)|| articlesLeft <= 0"
                    @click.prevent="
                        () => {
                            articleKeywords[option.value].push([]);
                            advancedTimes[option.value].push('10:00');
                        }
                    "
                >
                    <IconPlus />
                </Button>
            </div>
        </div>
    </div>
    <!-- Days of the week -->

    <!-- Schedule settings -->
    <div
        :class="[
            'mx-auto',
            (!isPreview || !isAccountFree) && 'mt-8 max-w-[300px]',
            isPreview && 'mt-5 flex flex-col md:flex-row gap-3 md:gap-5 md:max-w-[620px]',
        ]"
    >
        <!-- Time -->
        <TimeSelect
            class="mb-2.5 min-w-[120px]"
            :disabled="(isAccountFree && isPreview) || isAccountExpired"
            v-model="selectedTime"
            v-if="!isAdvancedSchedule"
        />

        <!-- Timezone -->
        <Select
            :class="[(!isPreview || !isAccountFree) && 'mb-8']"
            :options="timeZones"
            :disabled="true"
            v-model="selectedTimeZone"
        />
    </div>

    <div class="max-w-[300px] mx-auto">
        <!-- Toggle activity date -->

        <div class="flex justify-center w-full mb-3">
            <Toggle
                :class="(isPreview || isAccountFree) && 'pointer-events-none'"
                :inactive-text="$gettext('Disable')"
                :active-text="$gettext('Enable')"
                v-model="activityDateEnabled"
                :disabled="(isAccountFree && isPreview) || isAccountExpired"
            />
        </div>

        <!-- Activity dates -->
        <DateRangeSelect
            :class="(isPreview || isAccountFree || !activityDateEnabled) && 'pointer-events-none'"
            class="mb-8"
            v-model="selectedActivityDate"
            :disabled="isPreview || isAccountFree || !activityDateEnabled || isAccountExpired"
        />
    </div>
    <!-- Schedule settings -->

    <!-- Popup with upgrade info -->
    <Popup
        ref="upgradePopup"
        :cancel-button-text="$gettext('Maybe later')"
        :confirm-button-text="$gettext('Upgrade to paid plan')"
        @popup-confirm="router.push('/upgrade')"
        v-if="isPreview"
    >
        <div class="text-center">
            <IconWarning class="mb-4 mx-auto" />
            <h2 class="text-lg leading-lg font-bold">{{ $gettext('Upgrade needed') }}</h2>
            <p>
                {{ $gettext('Advanced scheduling is available only on a paid plan.') }}
                <br />
                {{ $gettext('Upgrade account to use this feature.') }}
            </p>
        </div>
    </Popup>
    <!-- Popup with upgrade info -->

    <!-- Keywords popup -->
    <PopupTextarea
        ref="keywordPopup"
        :cancel-button-text="$gettext('Cancel')"
        :confirm-button-text="$gettext('Edit keywords')"
        :heading="$gettext('Edit keywords')"
        :placeholder="$gettext('Use comma or enter for separating keywords')"
        @popup-confirm="updateKeyword"
        v-model="currentKeyword"
        v-if="isPreview"
    />
    <!-- Keywords popup -->
</template>

<style scoped></style>
