<?php

namespace MintyPHP\Module\Bookmarks\Repository;

use MintyPHP\DB;

class BookmarkNavigationRepository
{
    public function nextRootSortOrder(int $userId): int
    {
        if ($userId <= 0) {
            return 1;
        }

        $max = DB::selectValue(
            'select GREATEST(
                COALESCE((select max(sort_order) from user_bookmark_groups where user_id = ?), 0),
                COALESCE((select max(sort_order) from user_bookmarks where user_id = ? and group_id is NULL), 0)
            )',
            (string) $userId,
            (string) $userId
        );

        return max(1, ((int) $max) + 1);
    }

    public function updateRootSortOrders(int $userId, array $rootOrderPairs): bool
    {
        if ($userId <= 0 || $rootOrderPairs === []) {
            return false;
        }

        $groupPairs = [];
        $bookmarkPairs = [];
        $groupIds = [];
        $bookmarkIds = [];

        foreach ($rootOrderPairs as $pair) {
            $kind = trim((string) $pair['kind']);
            $id = (int) $pair['id'];
            $sortOrder = (int) $pair['sort_order'];
            if ($id <= 0 || $sortOrder <= 0 || ($kind !== 'group' && $kind !== 'bookmark')) {
                return false;
            }

            if ($kind === 'group') {
                $groupPairs[] = ['id' => $id, 'sort_order' => $sortOrder];
                $groupIds[] = $id;
                continue;
            }

            $bookmarkPairs[] = ['id' => $id, 'sort_order' => $sortOrder];
            $bookmarkIds[] = $id;
        }

        if ($groupPairs === [] && $bookmarkPairs === []) {
            return false;
        }

        if ($groupIds !== []) {
            $uniqueGroupIds = array_values(array_unique($groupIds));
            $groupCount = DB::selectValue(
                'select count(*) from user_bookmark_groups where user_id = ? and id in (???)',
                (string) $userId,
                array_map('strval', $uniqueGroupIds)
            );
            if ((int) $groupCount !== count($uniqueGroupIds)) {
                return false;
            }
        }

        if ($bookmarkIds !== []) {
            $uniqueBookmarkIds = array_values(array_unique($bookmarkIds));
            $bookmarkCount = DB::selectValue(
                'select count(*) from user_bookmarks where user_id = ? and group_id is NULL and id in (???)',
                (string) $userId,
                array_map('strval', $uniqueBookmarkIds)
            );
            if ((int) $bookmarkCount !== count($uniqueBookmarkIds)) {
                return false;
            }
        }

        $db = DB::handle();
        try {
            $db->begin_transaction();

            foreach ($groupPairs as $pair) {
                $updated = DB::update(
                    'update user_bookmark_groups set sort_order = ? where id = ? and user_id = ?',
                    (string) $pair['sort_order'],
                    (string) $pair['id'],
                    (string) $userId
                );
                if ($updated === false) {
                    $db->rollback();
                    return false;
                }
            }

            foreach ($bookmarkPairs as $pair) {
                $updated = DB::update(
                    'update user_bookmarks set sort_order = ? where id = ? and user_id = ? and group_id is NULL',
                    (string) $pair['sort_order'],
                    (string) $pair['id'],
                    (string) $userId
                );
                if ($updated === false) {
                    $db->rollback();
                    return false;
                }
            }

            $db->commit();
            return true;
        } catch (\Throwable) {
            try {
                $db->rollback();
            } catch (\Throwable) {
                // no-op
            }
            return false;
        }
    }
}
