# 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 pyarrow as pa


def _pandas_write_schema(table, schema):
    """Keep ignored events available for the normal row-kind NULL checks."""
    if table is None or not table.is_primary_key_table:
        return schema
    from pypaimon.write.row_kind import write_value_schema
    schema = write_value_schema(table, schema)
    options = table.options
    raw = options.options.to_map()
    if (raw.get('rowkind.field') is None
            or not (options.ignore_delete() or str(raw.get('ignore-update-before', 'false')).lower() == 'true')):
        return schema
    # Pandas checks top-level NOT NULL before Arrow reaches the writer. Only
    # relax the transport; the declared schema and nested fields stay intact.
    return pa.schema([field.with_nullable(True) for field in schema], metadata=schema.metadata)


def _pandas_write_batch(table, dataframe, schema, table_schema):
    """Retain event/routing inputs omitted from the physical write type."""
    # Convert the selected fields before building a wider transport. PyArrow
    # validates missing columns and can resolve selected values from a named
    # DataFrame index; filling a full DataFrame layout first would erase both.
    batch = pa.RecordBatch.from_pandas(dataframe, schema=_pandas_write_schema(table, schema))
    if table is not None and schema.names != table_schema.names:
        from pypaimon.table.bucket_mode import BucketMode
        required = list(table.partition_keys)
        if table.bucket_mode() == BucketMode.HASH_FIXED and table.options.bucket() > 1:
            required.extend(table.table_schema.bucket_keys)
        row_kind_field = table.options.options.to_map().get('rowkind.field')
        if row_kind_field is not None:
            required.append(row_kind_field)
        if not set(required).issubset(schema.names):
            extra_schema = pa.schema([field.with_nullable(True) for field in table_schema
                                      if field.name in required and field.name not in schema.names])
            extra = pa.RecordBatch.from_pandas(dataframe, schema=extra_schema)
            columns = dict(zip(batch.schema.names, batch.columns))
            columns.update(zip(extra.schema.names, extra.columns))
            # Only written/event/routing fields were converted. Do not touch
            # unwritten payloads, including live BLOB objects.
            fields = [field if field.name in schema.names else field.with_nullable(True) for field in table_schema]
            arrays = [columns[field.name] if field.name in columns else pa.nulls(batch.num_rows, field.type)
                      for field in fields]
            batch = pa.RecordBatch.from_arrays(arrays, schema=pa.schema(fields, metadata=table_schema.metadata))
    return batch


def _write_ray(writer, dataset, overwrite=False, concurrency=None, ray_remote_args=None,
               hash_fixed_precluster='auto', static_partition=None):
    """Share Ray coordination without constructing another local data writer."""
    from pypaimon.write.ray_datasink import write_paimon_dataset

    overwrite_partition = writer.static_partition if static_partition is None else static_partition
    return write_paimon_dataset(
        dataset, writer.table, overwrite=overwrite, static_partition=overwrite_partition,
        concurrency=concurrency, ray_remote_args=ray_remote_args,
        hash_fixed_precluster=hash_fixed_precluster,
        **writer._distributed_write_options(overwrite=overwrite or overwrite_partition is not None))


def postpone_distributed_write_options(table, bucket_plan, overwrite):
    """Build a distributed bucket plan before worker writers receive data."""
    from pypaimon.write.backend_dispatch import create_postpone_bucket_planner
    return {'postpone_bucket_planner': create_postpone_bucket_planner(
        table, known_num_buckets=(bucket_plan.as_dict() if bucket_plan is not None
                                  else {} if overwrite else None))}
