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

from typing import Any, Dict, List, Mapping, Optional, Sequence

import pyarrow as pa

from pypaimon.common.predicate import Predicate
from pypaimon.table.row.internal_row import InternalRow
from pypaimon.write.row_utils import require_columns


def _authorize_update(table):
    """Require the same whole-table grant as plan_all for fast paths."""
    from pypaimon.catalog.catalog_exception import TableNoPermissionException
    from pypaimon.read.auth_support import authorize

    query_auth = table.catalog_environment.table_query_auth(table.options, table.identifier)
    if authorize(table, query_auth, None) is not None:
        raise TableNoPermissionException(table.identifier)


def predicate_fields(predicate: Predicate) -> set:
    if predicate.field is not None:
        return {predicate.field}
    fields = set()
    for child in predicate.literals or []:
        fields.update(predicate_fields(child))
    return fields


def _validate_predicate_update(
        self, assignments: Mapping[str, Any], read_columns: Optional[Sequence[str]],
        has_callable: bool, has_array: bool):
    if not self.table.options.data_evolution_enabled():
        raise ValueError("update_by_predicate requires 'data-evolution.enabled' = 'true'.")
    if not self.table.options.row_tracking_enabled():
        raise ValueError("update_by_predicate requires 'row-tracking.enabled' = 'true'.")
    if not assignments:
        raise ValueError('assignments must not be empty.')
    if read_columns and (not has_callable):
        raise ValueError('read_columns requires a callable assignment.')
    if has_callable:
        if has_array:
            raise ValueError('Callable assignments cannot be combined with Arrow array assignments.')
        if not read_columns:
            raise ValueError('Callable assignments require read_columns.')
        for col in read_columns:
            if col not in self.table.field_names:
                raise ValueError(f'Read column {col} is not in table schema.')
    partition_keys = set(self.table.partition_keys)
    for col in assignments:
        if col not in self.table.field_names:
            raise ValueError(f'Column {col} is not in table schema.')
        if col in partition_keys:
            raise ValueError(f"update_by_predicate does not support updating partition column '{col}'.")


def _validate_inputs(self, data: pa.Table, upsert_keys: List[str], update_cols: Optional[List[str]]):
    """Validate inputs before processing."""
    if not self.table.options.data_evolution_enabled():
        raise ValueError("upsert_by_arrow_with_key requires 'data-evolution.enabled' = 'true'.")
    if not self.table.options.row_tracking_enabled():
        raise ValueError("upsert_by_arrow_with_key requires 'row-tracking.enabled' = 'true'.")
    if not upsert_keys:
        raise ValueError('upsert_keys must not be empty.')
    for key in upsert_keys:
        if key not in self.table.field_names:
            raise ValueError(f"upsert_key '{key}' is not in table schema fields: {self.table.field_names}")
        if key not in data.column_names:
            raise ValueError(f"upsert_key '{key}' is not in input data columns: {data.column_names}")
    partition_keys = self.table.partition_keys
    if partition_keys:
        missing_in_data = [pk for pk in partition_keys if pk not in data.column_names]
        if missing_in_data:
            raise ValueError(
                'For partitioned tables, input data must contain all partition key '
                f'columns. Missing: {missing_in_data}')
    if update_cols is not None:
        for col in update_cols:
            if col not in self.table.field_names:
                raise ValueError(
                    f"Column '{col}' in update_cols is not in table schema fields: {self.table.field_names}")
    if data.num_rows == 0:
        raise ValueError('Input data is empty.')


def _validate_row_inputs(self, values_by_name: Dict[str, Any],
                         upsert_keys: List[str], update_cols: Optional[List[str]]):
    if not self.table.options.data_evolution_enabled():
        raise ValueError("upsert_by_key requires 'data-evolution.enabled' = 'true'.")
    if not self.table.options.row_tracking_enabled():
        raise ValueError("upsert_by_key requires 'row-tracking.enabled' = 'true'.")
    if not upsert_keys:
        raise ValueError('upsert_keys must not be empty.')
    for key in upsert_keys:
        if key not in self.table.field_names:
            raise ValueError(f"upsert_key '{key}' is not in table schema fields: {self.table.field_names}")
    unknown_fields = [field_name for field_name in values_by_name if field_name not in self.table.field_names]
    if unknown_fields:
        raise ValueError(
            f'upsert_by_key got row field(s) {unknown_fields} '
            f'that are not in table schema fields: {self.table.field_names}')
    require_columns(values_by_name, upsert_keys, 'upsert_by_key')
    require_columns(values_by_name, self.table.partition_keys, 'upsert_by_key')
    if update_cols is not None:
        for col in update_cols:
            if col not in self.table.field_names:
                raise ValueError(
                    f"Column '{col}' in update_cols is not in table schema fields: {self.table.field_names}")


def _normalize_rows(rows) -> List:
    if isinstance(rows, InternalRow):
        return [rows]
    return list(rows)
