# 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.

"""Transport row Blob streams into the core URI copy path."""

from collections.abc import Mapping
from decimal import Decimal
from uuid import uuid4

import pyarrow as pa

from pypaimon.schema.data_types import ArrayType, MapType, PyarrowFieldParser, is_blob_file_field
from pypaimon.table.row.blob import Blob, BlobDescriptor
from pypaimon.write.row_utils import inline_blob_value, value_for_arrow


class _BlobRowReader:
    def __init__(self, blob):
        self.blob = blob

    def new_input_stream(self, uri):
        return self.blob.new_input_stream()


class NativeBlobRows:
    """Expose each Python Blob lazily, without opening or materializing it.

    The synthetic descriptors only transport live objects for this operation.
    Core copies their payloads into normal .blob records; these URIs must never
    become stored descriptors. A new reader is kept for each Blob object so
    the core cannot reuse an unrelated Python stream.
    """

    def __init__(self, fallback=None):
        self.readers = {}
        self._consumed = set()
        self.fallback = fallback

    def _supports_uri(self, uri):
        # Ordinary descriptors retain the core FileIO/HTTP path. A configured
        # application factory owns other URIs and its errors must propagate.
        if uri in self.readers:
            return True
        if self.fallback is None:
            return False
        if hasattr(self.fallback, '_supports_uri'):
            return self.fallback._supports_uri(uri)
        return True

    def create(self, uri):
        if uri in self.readers:
            self._consumed.add(uri)
            return self.readers[uri]
        return self.fallback.create(uri)

    def release_consumed(self):
        """Release inputs consumed by core, retaining unplanned partition rows."""
        for uri in self._consumed:
            self.readers.pop(uri, None)
        self._consumed.clear()

    def clear(self):
        self.readers.clear()
        self._consumed.clear()

    def to_batch(self, table, rows, names):
        """Transport existing row values; core owns physical input validation."""
        descriptor_fields = table.options.blob_descriptor_fields()
        view_fields = table.options.blob_view_fields()
        fields = []
        columns = []
        for name in names:
            field = table.field_dict[name]
            arrow_field = PyarrowFieldParser.from_paimon_field(field)
            inline = name in descriptor_fields or name in view_fields
            if is_blob_file_field(field) and not inline:
                if isinstance(field.type, MapType) and not table.is_primary_key_table:
                    entries = pa.struct([
                        pa.field('key', arrow_field.type.key_type),
                        arrow_field.type.item_field.with_name('value'),
                    ])
                    arrow_field = pa.field(name, pa.list_(entries), nullable=arrow_field.nullable)
                values = [self.encode(row[name], field.type) for row in rows]
                if (isinstance(field.type, MapType) and not table.is_primary_key_table
                        and pa.types.is_decimal(arrow_field.type.value_type[0].type)):
                    # Preserve arbitrary source scale. The core rounds and checks
                    # precision before serializing the declared decimal key.
                    def key_text(key):
                        if key is None:
                            return None
                        if not isinstance(key, Decimal):
                            raise ValueError('MAP<X, BLOB> DECIMAL key must be a decimal.Decimal.')
                        return format(key, 'f')
                    values = [None if value is None else [(key_text(key), item) for key, item in value]
                              for value in values]
                    entries = arrow_field.type.value_type
                    entries = pa.struct([entries[0].with_type(pa.string()), entries[1]])
                    arrow_field = arrow_field.with_type(pa.list_(entries))
            else:
                values = [value_for_arrow(inline_blob_value(
                    row[name], name in descriptor_fields, name in view_fields), field)
                    for row in rows]
            fields.append(arrow_field)
            columns.append(pa.array(values, type=arrow_field.type))
        return pa.RecordBatch.from_arrays(columns, schema=pa.schema(fields))

    def encode(self, value, data_type):
        if hasattr(value, 'as_py'):
            value = value.as_py()
        if value is None:
            return None
        if isinstance(data_type, ArrayType):
            if isinstance(value, (bytes, bytearray, str)):
                raise ValueError('ARRAY<BLOB> field value must be a list or tuple.')
            return [self.encode(item, data_type.element) for item in value]
        if isinstance(data_type, MapType):
            if isinstance(value, (bytes, bytearray, str)) or not hasattr(value, '__iter__'):
                raise ValueError('MAP<X, BLOB> field value must be a mapping or key/value pairs')
            entries = value.items() if isinstance(value, Mapping) else value
            result = []
            for entry in entries:
                if not isinstance(entry, (list, tuple)) or len(entry) != 2:
                    raise ValueError('MAP<X, BLOB> entries must be key/value pairs')
                result.append((entry[0], self.encode(entry[1], data_type.value)))
            return result
        if isinstance(value, Blob):
            if any(value is placeholder for placeholder in (
                    Blob.PLACE_HOLDER, Blob.ARRAY_PLACE_HOLDER, Blob.MAP_PLACE_HOLDER)):
                raise ValueError('Blob placeholders are reserved for unchanged rows.')
            uri = 'pypaimon-blob-row://' + uuid4().hex
            self.readers[uri] = _BlobRowReader(value)
            return BlobDescriptor(uri, 0, -1).serialize()
        return value
