/*
 * Copyright (C) Contributors to the Suwayomi project
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

import {
    ReaderProgressBarProps,
    TReaderProgressCurrentPage,
} from '@/features/reader/overlay/progress-bar/ReaderProgressBar.types.ts';
import { getOptionForDirection as getOptionForDirectionImpl } from '@/features/theme/services/ThemeCreator.ts';
import { ProgressBarPosition } from '@/features/reader/Reader.types.ts';
import { coerceIn } from '@/lib/HelperFunctions.ts';

export const getPage = (pageIndex: number, pages: ReaderProgressBarProps['pages']): TReaderProgressCurrentPage => {
    const pagesIndex = pages.findIndex(({ primary, secondary }) =>
        [primary.index, secondary?.index].includes(pageIndex),
    );
    const page = pages[coerceIn(pagesIndex, 0, pages.length - 1)];
    return {
        ...page,
        pagesIndex,
    };
};

/**
 * for the double page mode the secondary page index has to be used to be able to correctly detect if the last page is visible
 *
 */
export const getNextIndexFromPage = (page: ReaderProgressBarProps['pages'][number]) =>
    page.secondary?.index ?? page.primary.index;

export const getNextPageIndex = (
    offset: 'previous' | 'next',
    pagesIndex: number,
    pages: ReaderProgressBarProps['pages'],
): number => {
    switch (offset) {
        case 'previous':
            return getNextIndexFromPage(pages[Math.max(0, pagesIndex - 1)]);
        case 'next':
            return getNextIndexFromPage(pages[Math.min(pages.length - 1, pagesIndex + 1)]);
        default:
            throw new Error(`Unexpected offset "${offset}"`);
    }
};

export const getPageForMousePos = (
    coordinates: { clientX: number; clientY: number },
    element: HTMLElement,
    pages: ReaderProgressBarProps['pages'],
    isHorizontalPosition: boolean,
    fullSegmentClicks: boolean,
    getOptionForDirection: typeof getOptionForDirectionImpl,
): ReaderProgressBarProps['pages'][number] => {
    const pos = isHorizontalPosition ? coordinates.clientX : coordinates.clientY;

    const { paddingTop, paddingBottom, paddingLeft, paddingRight } = getComputedStyle(element);
    const elementRect = element.getBoundingClientRect();
    const padding = isHorizontalPosition
        ? parseFloat(paddingLeft) + parseFloat(paddingRight)
        : parseFloat(paddingTop) + parseFloat(paddingBottom);

    const rectPos = isHorizontalPosition ? elementRect.left : elementRect.top;
    const rectSizeWithPadding = isHorizontalPosition ? elementRect.width : elementRect.height;
    const rectSize = rectSizeWithPadding - padding;

    const mousePosRelativeToProgressBar = pos - rectPos - padding / 2;

    const totalPages = pages.length - Number(!fullSegmentClicks);

    const segmentWidth = rectSize / totalPages;
    const clickedSegmentIndex = Math.floor(mousePosRelativeToProgressBar / segmentWidth);
    const segmentMiddlePoint = (clickedSegmentIndex + (fullSegmentClicks ? 1 : 0.5)) * segmentWidth;
    const actualClickedSegmentIndex =
        mousePosRelativeToProgressBar <= segmentMiddlePoint ? clickedSegmentIndex : clickedSegmentIndex + 1;

    const minPageIndex = Math.max(0, actualClickedSegmentIndex);
    const maxPageIndex = Math.min(minPageIndex, pages.length - 1);
    const newPageIndex = getOptionForDirection(maxPageIndex, pages.length - 1 - maxPageIndex);

    return pages[newPageIndex];
};

export const getProgressBarPositionInfo = (
    position: ProgressBarPosition,
): {
    isBottom: boolean;
    isLeft: boolean;
    isRight: boolean;
    isHorizontal: boolean;
    isVertical: boolean;
} => {
    const isBottom = position === ProgressBarPosition.BOTTOM;
    const isLeft = position === ProgressBarPosition.LEFT;
    const isRight = position === ProgressBarPosition.RIGHT;
    const isHorizontal = isBottom;
    const isVertical = isLeft || isRight;

    return {
        isBottom,
        isLeft,
        isRight,
        isHorizontal,
        isVertical,
    };
};
