<script setup lang="ts">
import { ClockIcon } from '@heroicons/vue/20/solid';
import CardTitle from '@/packages/ui/src/CardTitle.vue';
import { usePage } from '@inertiajs/vue3';
import { type User } from '@/types/models';
import { computed, onMounted, watch } from 'vue';
import { getDayJsInstance } from '@/packages/ui/src/utils/time';
import { useBreaksEnabled } from '@/packages/ui/src/utils/useBreaksEnabled';

import { getLastWorkTimeEntry, useCurrentTimeEntryStore } from '@/utils/useCurrentTimeEntry';
import { storeToRefs } from 'pinia';
import { getCurrentOrganizationId } from '@/utils/useUser';
import { useLocalStorage } from '@vueuse/core';
import { useOrganizationQuery } from '@/utils/useOrganizationQuery';
import { switchOrganization } from '@/utils/useOrganization';
import { useProjectsQuery } from '@/utils/useProjectsQuery';
import { useTasksQuery } from '@/utils/useTasksQuery';
import { useTagsQuery } from '@/utils/useTagsQuery';
import { useClientsQuery } from '@/utils/useClientsQuery';
import { useTagsStore } from '@/utils/useTags';
import { useProjectsStore } from '@/utils/useProjects';
import TimeTrackerControls from '@/packages/ui/src/TimeTracker/TimeTrackerControls.vue';
import type { TimeTrackerMode } from '@/packages/ui/src/TimeTracker/types';
import type {
    CreateClientBody,
    CreateProjectBody,
    CreateTimeEntryBody,
    Project,
    Tag,
} from '@/packages/api/src';
import TimeTrackerRunningInDifferentOrganizationOverlay from '@/packages/ui/src/TimeTracker/TimeTrackerRunningInDifferentOrganizationOverlay.vue';
import TimeTrackerMoreOptionsDropdown from '@/packages/ui/src/TimeTracker/TimeTrackerMoreOptionsDropdown.vue';
import TimeEntryCreateModal from '@/packages/ui/src/TimeEntry/TimeEntryCreateModal.vue';
import { useClientsStore } from '@/utils/useClients';
import { getOrganizationCurrencyString } from '@/utils/money';
import { isAllowedToPerformPremiumAction } from '@/utils/billing';
import { canCreateProjects } from '@/utils/permissions';
import { ref } from 'vue';
import { useNotificationsStore } from '@/utils/notification';
import { useTimeEntriesMutations } from '@/utils/useTimeEntriesMutations';
import { useTimeEntriesInfiniteQuery } from '@/utils/useTimeEntriesInfiniteQuery';

const page = usePage<{
    auth: {
        user: User;
    };
}>();
const dayjs = getDayJsInstance();

const { organization } = useOrganizationQuery(getCurrentOrganizationId()!);
const breaksEnabled = useBreaksEnabled(organization);

const currentTimeEntryStore = useCurrentTimeEntryStore();
const { currentTimeEntry, isActive, isOnBreak, now } = storeToRefs(currentTimeEntryStore);
const { startLiveTimer, stopLiveTimer, setActiveState, startBreak, resumeWorkAfterBreak } =
    currentTimeEntryStore;

const { projects } = useProjectsQuery();
const { tasks } = useTasksQuery();
const { clients } = useClientsQuery();

const emit = defineEmits<{
    change: [];
}>();

const showManualTimeEntryModal = ref(false);

const { createTimeEntry: createTimeEntryMutation, deleteTimeEntry } = useTimeEntriesMutations();
const { data: timeEntriesData } = useTimeEntriesInfiniteQuery();
const timeEntries = computed(() => timeEntriesData.value?.pages.flatMap((page) => page.data) || []);
const lastWorkTimeEntry = computed(() => getLastWorkTimeEntry(timeEntries.value));
const canResumeAfterBreak = computed(() => lastWorkTimeEntry.value !== null);

watch(isActive, () => {
    if (isActive.value) {
        startLiveTimer();
    } else {
        stopLiveTimer();
    }
    emit('change');
});

onMounted(async () => {
    if (page.props.auth.user.current_team_id) {
        await currentTimeEntryStore.fetchCurrentTimeEntry();
        now.value = dayjs().utc();
    }
});

function updateTimeEntry() {
    if (currentTimeEntry.value.id) {
        useCurrentTimeEntryStore().updateTimer();
    }
}

const isRunningInDifferentOrganization = computed(() => {
    return (
        currentTimeEntry.value.organization_id &&
        getCurrentOrganizationId() &&
        currentTimeEntry.value.organization_id !== getCurrentOrganizationId()
    );
});

async function createProject(project: CreateProjectBody): Promise<Project | undefined> {
    const newProject = await useProjectsStore().createProject(project);
    if (newProject) {
        currentTimeEntry.value.project_id = newProject.id;
    }
    return newProject;
}
async function createClient(client: CreateClientBody) {
    return await useClientsStore().createClient(client);
}

function switchToTimeEntryOrganization() {
    if (currentTimeEntry.value.organization_id) {
        switchOrganization(currentTimeEntry.value.organization_id);
    }
}
async function createTag(tag: string): Promise<Tag | undefined> {
    return await useTagsStore().createTag(tag);
}

async function createTimeEntry(timeEntry: Omit<CreateTimeEntryBody, 'member_id'>) {
    await createTimeEntryMutation(timeEntry);
    showManualTimeEntryModal.value = false;
}

async function resumePreviousWorkAfterBreak() {
    const timeEntry = lastWorkTimeEntry.value;
    if (!timeEntry) {
        return;
    }
    await resumeWorkAfterBreak(timeEntry);
}

async function createTimeEntryFromCurrentEntry() {
    const { start, end, description, project_id, task_id, billable, tags } = currentTimeEntry.value;
    await createTimeEntry({ start, end, description, project_id, task_id, billable, tags });
    currentTimeEntryStore.$reset();
}

const { handleApiRequestNotifications } = useNotificationsStore();

async function discardCurrentTimeEntry() {
    if (currentTimeEntry.value.id) {
        await handleApiRequestNotifications(
            () => deleteTimeEntry(currentTimeEntry.value.id),
            'Time entry discarded successfully',
            'Failed to discard time entry'
        );
        await currentTimeEntryStore.fetchCurrentTimeEntry();
    }
}

// Time tracker UI mode is a per-device UI preference, stored client-side and keyed by organization
const timeTrackerMode = useLocalStorage<TimeTrackerMode>(
    `solidtime/time-tracker-mode/${getCurrentOrganizationId()}`,
    'project'
);

function toggleTimeTrackerMode() {
    timeTrackerMode.value = timeTrackerMode.value === 'simple' ? 'project' : 'simple';
}

const { tags } = useTagsQuery();
</script>

<template>
    <TimeEntryCreateModal
        v-model:show="showManualTimeEntryModal"
        :enable-estimated-time="isAllowedToPerformPremiumAction()"
        :create-project="createProject"
        :create-client="createClient"
        :create-tag="createTag"
        :create-time-entry="createTimeEntry"
        :currency="getOrganizationCurrencyString()"
        :can-create-project="canCreateProjects()"
        :organization-billable-rate="organization?.billable_rate ?? null"
        :projects
        :tasks
        :tags
        :clients></TimeEntryCreateModal>
    <CardTitle title="Time Tracker" :icon="ClockIcon"></CardTitle>
    <div class="relative pt-1.5">
        <TimeTrackerRunningInDifferentOrganizationOverlay
            v-if="isRunningInDifferentOrganization"
            @switch-organization="
                switchToTimeEntryOrganization
            "></TimeTrackerRunningInDifferentOrganizationOverlay>

        <div class="flex w-full items-center gap-2">
            <div class="flex w-full items-center gap-2">
                <div class="flex-1">
                    <TimeTrackerControls
                        v-model:current-time-entry="currentTimeEntry"
                        v-model:live-timer="now"
                        :create-project
                        :enable-estimated-time="isAllowedToPerformPremiumAction()"
                        :can-create-project="canCreateProjects()"
                        :organization-billable-rate="organization?.billable_rate ?? null"
                        :create-client
                        :clients
                        :tags
                        :tasks
                        :projects
                        :time-entries
                        :create-tag
                        :is-active
                        :is-on-break="isOnBreak"
                        :breaks-enabled="breaksEnabled"
                        :can-resume-after-break="canResumeAfterBreak"
                        :resume-description="lastWorkTimeEntry?.description ?? null"
                        :time-tracker-mode="timeTrackerMode"
                        :currency="getOrganizationCurrencyString()"
                        @start-live-timer="startLiveTimer"
                        @stop-live-timer="stopLiveTimer"
                        @start-timer="setActiveState(true)"
                        @stop-timer="setActiveState(false)"
                        @start-break="startBreak"
                        @resume-after-break="resumePreviousWorkAfterBreak"
                        @update-time-entry="updateTimeEntry"
                        @create-time-entry="createTimeEntryFromCurrentEntry"></TimeTrackerControls>
                </div>
                <TimeTrackerMoreOptionsDropdown
                    :has-active-timer="isActive"
                    :time-tracker-mode="timeTrackerMode"
                    :is-on-break="isOnBreak"
                    :breaks-enabled="breaksEnabled"
                    @manual-entry="showManualTimeEntryModal = true"
                    @start-break="startBreak"
                    @toggle-time-tracker-mode="toggleTimeTrackerMode"
                    @discard="discardCurrentTimeEntry"></TimeTrackerMoreOptionsDropdown>
            </div>
        </div>
    </div>
</template>
