# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

import heapq
import math
from dataclasses import dataclass
from functools import cmp_to_key
from typing import Callable, List

from pypaimon.manifest.schema.data_file_meta import DataFileMeta
from pypaimon.table.row.generic_row import GenericRow


@dataclass
class SortedRun:
    """
    A SortedRun is a list of files sorted by their keys.
    The key intervals [minKey, maxKey] of these files do not overlap.
    """
    files: List[DataFileMeta]


class IntervalPartition:
    """
    Algorithm to partition several data files into the minimum number of SortedRuns.
    """

    def __init__(self, input_files: List[DataFileMeta]):
        self.files = input_files.copy()
        self.key_comparator = default_key_comparator
        self.files.sort(key=cmp_to_key(self._compare_files))

    def partition(self) -> List[List[SortedRun]]:
        result = []
        section: List[DataFileMeta] = []
        bound = None

        for meta in self.files:
            if section and self.key_comparator(meta.min_key, bound) > 0:
                result.append(self._partition_section(section))
                section.clear()
                bound = None
            section.append(meta)
            if bound is None or self.key_comparator(meta.max_key, bound) > 0:
                bound = meta.max_key

        if section:
            result.append(self._partition_section(section))
        return result

    def _partition_section(self, metas: List[DataFileMeta]) -> List[SortedRun]:
        heap: List[HeapRun] = []
        first_run = [metas[0]]
        heapq.heappush(heap, HeapRun(first_run, self.key_comparator))
        for i in range(1, len(metas)):
            meta = metas[i]

            earliest_finishing_run = heap[0]
            last_max_key = earliest_finishing_run.run[-1].max_key
            if self.key_comparator(meta.min_key, last_max_key) > 0:
                top = heapq.heappop(heap)
                top.run.append(meta)
                heapq.heappush(heap, top)
            else:
                new_run = [meta]
                heapq.heappush(heap, HeapRun(new_run, self.key_comparator))

        return [SortedRun(files=h.run) for h in heap]

    def _compare_files(self, f1: DataFileMeta, f2: DataFileMeta) -> int:
        min_key_cmp = self.key_comparator(f1.min_key, f2.min_key)
        if min_key_cmp != 0:
            return min_key_cmp
        return self.key_comparator(f1.max_key, f2.max_key)


@dataclass
class HeapRun:
    run: List[DataFileMeta]
    comparator: Callable[[GenericRow, GenericRow], int]

    def __lt__(self, other) -> bool:
        my_last_max = self.run[-1].max_key
        other_last_max = other.run[-1].max_key
        return self.comparator(my_last_max, other_last_max) < 0


def default_key_comparator(key1: GenericRow, key2: GenericRow) -> int:
    if not key1 or not key1.values:
        if not key2 or not key2.values:
            return 0
        return -1
    if not key2 or not key2.values:
        return 1

    min_field_count = min(len(key1.values), len(key2.values))
    for i in range(min_field_count):
        val1 = key1.values[i]
        val2 = key2.values[i]
        if val1 is None and val2 is None:
            continue
        if val1 is None:
            return -1
        if val2 is None:
            return 1
        # Preserve Java's ordering of signed zeros in composite key bounds.
        if (isinstance(val1, float) and isinstance(val2, float)
                and val1 == 0.0 and val2 == 0.0):
            sign1, sign2 = math.copysign(1.0, val1), math.copysign(1.0, val2)
            if sign1 != sign2:
                return -1 if sign1 < sign2 else 1
        if val1 < val2:
            return -1
        elif val1 > val2:
            return 1

    if len(key1.values) < len(key2.values):
        return -1
    elif len(key1.values) > len(key2.values):
        return 1
    else:
        return 0
