package convert

import (
	

	
	
	

	
)

func ( parquet.Field) (arrow.Field, error) {
	,  := ParquetNodeToType()
	if  != nil {
		return arrow.Field{}, 
	}

	return arrow.Field{
		Name:     .Name(),
		Type:     ,
		Nullable: .Optional(),
	}, nil
}

// ParquetNodeToType converts a parquet node to an arrow type.
// Rules from: https://github.com/apache/parquet-format/blob/master/LogicalTypes.md
func ( parquet.Node) (arrow.DataType, error) {
	if !.Leaf() {
		switch {
		case hasMapFields():
			return mapType()
		case hasListFields():
			return listType()
		default:
			 := make([]arrow.Field, 0, len(.Fields()))
			for ,  := range .Fields() {
				,  := ParquetFieldToArrowField()
				if  != nil {
					return nil, 
				}
				 = append(, )
			}
			return arrow.StructOf(...), nil
		}
	}

	 := .Type()
	 := .LogicalType()
	var  arrow.DataType
	switch {
	case  != nil:
		switch {
		case .UTF8 != nil:
			 := .Encoding()
			switch  {
			case nil:
				 = &arrow.BinaryType{}
			default:
				switch .Encoding() {
				// TODO(asubiotto): Should we remove this check for a deprecated
				// format?
				//nolint:staticcheck
				case format.PlainDictionary:
					fallthrough
				case format.RLEDictionary:
					 = &arrow.DictionaryType{
						IndexType: &arrow.Uint32Type{},
						ValueType: &arrow.BinaryType{},
					}
				default:
					 = &arrow.BinaryType{}
				}
			}
		case .Integer != nil:
			switch .Integer.BitWidth {
			case 64:
				if .Integer.IsSigned {
					 = &arrow.Int64Type{}
				} else {
					 = &arrow.Uint64Type{}
				}
			default:
				return nil, errors.New("unsupported int bit width")
			}
		default:
			return nil, errors.New("unsupported logical type: " + .Type().String())
		}
	case .Kind() == parquet.Boolean:
		 = &arrow.BooleanType{}
	case .Kind() == parquet.Double:
		 = &arrow.Float64Type{}
	default:
		return nil, errors.New("unsupported type: " + .Type().String())
	}

	if .Repeated() {
		 = arrow.ListOf()
	}

	return , nil
}

// GetWriter create a value writer from a parquet node.
func ( int,  parquet.Node) (writer.NewWriterFunc, error) {
	,  := ParquetNodeToType()
	if  != nil {
		return nil, 
	}

	 := false
	if ,  := .(*arrow.ListType);  {
		// Unwrap the list type.
		 = true
		 = .Elem()
	}

	var  writer.NewWriterFunc
	switch .(type) {
	case *arrow.BinaryType:
		 = writer.NewBinaryValueWriter
	case *arrow.Int64Type:
		 = writer.NewInt64ValueWriter
	case *arrow.Uint64Type:
		 = writer.NewUint64ValueWriter
	case *arrow.MapType:
		 = writer.NewMapWriter
	case *arrow.StructType:
		 = writer.NewStructWriterFromOffset()
	case *arrow.BooleanType:
		 = writer.NewBooleanValueWriter
	case *arrow.Float64Type:
		 = writer.NewFloat64ValueWriter
	case *arrow.DictionaryType:
		 = writer.NewDictionaryValueWriter
	default:
		return nil, errors.New("unsupported type: " + .Type().String())
	}

	if .Repeated() ||  {
		// TODO(asubiotto): We should use arrow.ListOfNonNullable if
		// n.Optional(). The problem is that it doesn't seem like the arrow
		// builder stores the nullability (NewArray always uses ListOf).
		return writer.NewListValueWriter(), nil
	}
	return , nil
}

// https://github.com/apache/parquet-format/blob/master/LogicalTypes.md#maps
func hasMapFields( parquet.Node) bool {
	// toplevel group requiredto be repeated group key_value with
	if len(.Fields()) != 1 || !.Fields()[0].Repeated() || .Fields()[0].Name() != "key_value" {
		return false
	}

	// can only be two fields, a key field and an optional value field
	if len(.Fields()[0].Fields()) < 1 || len(.Fields()[0].Fields()) > 2 {
		return false
	}

	// Find and validate key field
	for ,  := range .Fields()[0].Fields() {
		if .Name() == "key" && !.Required() {
			return false
		}
	}

	return true
}

// https://github.com/apache/parquet-format/blob/master/LogicalTypes.md#lists
func hasListFields( parquet.Node) bool {
	if (!.Optional() && !.Required()) || len(.Fields()) != 1 {
		return false
	}

	 := .Fields()[0]
	if .Name() != "list" || !.Repeated() || len(.Fields()) != 1 {
		return false
	}

	 := .Fields()[0]
	return .Required() || .Optional()
}

func mapType( parquet.Node) (arrow.DataType, error) {
	var  arrow.DataType
	var  arrow.DataType
	var  error
	 = &arrow.BooleanType{} // Default to boolean types for the value
	for ,  := range .Fields()[0].Fields() {
		switch .Name() {
		case "key":
			,  = ParquetNodeToType()
			if  != nil {
				return nil, 
			}
		case "value":
			,  = ParquetNodeToType()
			if  != nil {
				return nil, 
			}
		}
	}

	return arrow.MapOf(, ), nil
}

func listType( parquet.Node) (arrow.DataType, error) {
	,  := ParquetNodeToType(.Fields()[0].Fields()[0])
	if  != nil {
		return nil, 
	}
	return arrow.ListOf(), nil
}