from __future__ import annotations
import typing
import json

try:
    import fiona
    HAS_FIONA = True
except ImportError:
    HAS_FIONA = False

from ..base import BaseFileIterable, BaseCodec


class GeoPackageIterable(BaseFileIterable):
    datamode = 'binary'
    
    def __init__(self, filename: str = None, stream: typing.IO = None, codec: BaseCodec = None,
                 mode='r', layer: str = None, options: dict = {}):
        if not HAS_FIONA:
            raise ImportError("fiona library is required for GeoPackage support. Install it with: pip install fiona")
        
        super(GeoPackageIterable, self).__init__(filename, stream, codec=codec, mode=mode,
                                                 binary=True, encoding='utf8', options=options)
        self.layer = layer
        if 'layer' in options:
            self.layer = options['layer']
        self.reset()
    
    def reset(self):
        super(GeoPackageIterable, self).reset()
        self.features = []
        self.pos = 0
        self.collection = None
        
        if self.mode == 'r':
            try:
                # Open GeoPackage
                if self.layer:
                    self.collection = fiona.open(self.filename, layer=self.layer, mode='r')
                else:
                    # Use first layer if not specified
                    self.collection = fiona.open(self.filename, mode='r')
                
                # Read all features
                for feature in self.collection:
                    # Convert fiona feature to GeoJSON-like format
                    geojson_feature = {
                        'type': 'Feature',
                        'properties': feature.get('properties', {}),
                        'geometry': feature.get('geometry', {})
                    }
                    self.features.append(geojson_feature)
                
                self.iterator = iter(self.features)
            except Exception as e:
                self.features = []
                self.iterator = iter(self.features)
        elif self.mode in ['w', 'wr']:
            # Initialize writer
            self.writer = None
            self.writer_initialized = False
    
    @staticmethod
    def id() -> str:
        return 'geopackage'
    
    @staticmethod
    def is_flatonly() -> bool:
        return False
    
    @staticmethod
    def has_totals():
        """Has totals indicator"""
        return True
    
    def totals(self):
        """Returns file totals"""
        if hasattr(self, 'features'):
            return len(self.features)
        return 0
    
    def read(self) -> dict:
        """Read single GeoPackage feature"""
        feature = next(self.iterator)
        self.pos += 1
        return feature
    
    def read_bulk(self, num: int = 10) -> list[dict]:
        """Read bulk GeoPackage features"""
        chunk = []
        for n in range(0, num):
            try:
                chunk.append(self.read())
            except StopIteration:
                break
        return chunk
    
    def write(self, record: dict):
        """Write single GeoPackage feature"""
        if not HAS_FIONA:
            raise ImportError("fiona library is required for GeoPackage support")
        
        # Initialize writer on first write
        if not hasattr(self, 'writer_initialized') or not self.writer_initialized:
            # Determine schema from first record
            geometry = record.get('geometry', {})
            properties = record.get('properties', {})
            
            # Determine geometry type
            geom_type = geometry.get('type') if geometry else None
            
            # Create schema
            schema = {
                'geometry': geom_type or 'Unknown',
                'properties': {}
            }
            
            # Add property schemas
            for key, value in properties.items():
                if isinstance(value, int):
                    schema['properties'][key] = 'int'
                elif isinstance(value, float):
                    schema['properties'][key] = 'float'
                elif isinstance(value, bool):
                    schema['properties'][key] = 'bool'
                else:
                    schema['properties'][key] = 'str'
            
            # Create driver options
            driver = 'GPKG'
            crs = 'EPSG:4326'  # Default to WGS84
            
            # Open writer
            if self.layer:
                self.writer = fiona.open(self.filename, 'w', driver=driver, layer=self.layer,
                                        schema=schema, crs=crs)
            else:
                self.writer = fiona.open(self.filename, 'w', driver=driver,
                                        schema=schema, crs=crs)
            
            self.writer_initialized = True
        
        # Write feature in fiona format
        fiona_feature = {
            'type': 'Feature',
            'properties': record.get('properties', {}),
            'geometry': record.get('geometry', {})
        }
        
        self.writer.write(fiona_feature)
        self.pos += 1
    
    def write_bulk(self, records: list[dict]):
        """Write bulk GeoPackage features"""
        for record in records:
            self.write(record)
    
    def close(self):
        """Close GeoPackage"""
        if hasattr(self, 'writer') and self.writer is not None:
            self.writer.close()
        if hasattr(self, 'collection') and self.collection is not None:
            self.collection.close()
        super(GeoPackageIterable, self).close()
