from qgis.PyQt.QtCore import (
  QVariant
  )
from qgis.core import (
  QgsProcessingFeedback,
  QgsProcessingContext,
  QgsField,
  QgsFields,
  QgsFeature,
  QgsVectorLayer
  )

from ..algabstract import algabstract

class initabstract(algabstract):
    
  def __init__(self):
    super().__init__()
    self.PK = 1
    self.INPUT_LAYER = None  
    self.FIELDS_INIT = None
    self.FIELDS_REQUIRED = {"PK": {"TYPE": QVariant.Int, "DEFAULT_VALUE": None}}
    self.FIELDS_ADD = {} # additional fields, normally equals to FIELDS_REQUIRED_COMMON
    self.FIELDS_FROM = {} # where the field comes from, "INPUT" or "ADD
    

  # set the fields that are added / overwritten / not changed
  def setFieldsDict(self, parameters: dict, context: QgsProcessingContext, feedback: QgsProcessingFeedback, fields_input:QgsFields = QgsFields(), overwrite: bool = False) -> None:
    # initialize the list of the additional fields
    self.FIELDS_ADD.update(self.FIELDS_REQUIRED)
        
    # fields that are contained in the input layer are labelled as "INPUT"
    for fld_name in fields_input.names():
      self.FIELDS_FROM.update({fld_name: "INPUT"})
    
    # list up all the additional layers, for giving the information to the user
    fields_output = fields_input
    fld_names_added = []
    fld_names_overwritten = []
    # for each field in FIELDS_ADD, check whether it is added to the fields_init
    for fld_name, fld_info in self.FIELDS_ADD.items():
      # if it is not contained in the fields_init, just add it
      if fld_name.lower() not in map(lambda x: x.lower(), fields_output.names()):
        fields_output.append(QgsField(fld_name, fld_info["TYPE"]))
        self.FIELDS_FROM.update({fld_name: "ADD"})
        fld_names_added.append(fld_name)
      # else, check whether it is overwritten
      else:
        # if the overwrite flag is True, overwrite it and update the FIELDS_FROM
        # regarding the overwritten fields, default values are used
        if overwrite:
          self.FIELDS_FROM.update({fld_name: "ADD"})
          fld_names_overwritten.append(fld_name)
    
    # the pk field is always overwritten
    self.FIELDS_FROM.update({"PK": "ADD"})
    
    # ok, provide the information to the user
    if len(fld_names_added) > 0:
      feedback.pushInfo(self.tr("Append fields: ") + ",".join(fld_names_added))
    if len(fld_names_overwritten) > 0:
      feedback.pushInfo(self.tr("Overwritten fields: ") + ",".join(fld_names_overwritten))
    
    self.FIELDS_INIT = fields_output
  
  # reset the counter
  def resetPk(self):
    self.PK = 1
    
  # add features to the sink, based on the fields dictionaries  
  def addFeaturesToSink(self, sink, dest_id, layer: QgsVectorLayer = None):
    
    if layer is None:
      return
    
    # add features
    for ft in layer.getFeatures():
      # initialize the feature
      new_ft = QgsFeature(self.FIELDS_INIT)
      new_ft.setGeometry(ft.geometry())
      
      for fld_name, source in self.FIELDS_FROM.items():
        # the fields contained in the input layer are copied
        if source == "INPUT":
          val = ft[fld_name]
          
          # if val is QVariant NULL
          if isinstance(val, QVariant) and QVariant.isNull(val):
            new_ft[fld_name] = val
          # if no values in input layer and it is required, use the default value
          elif fld_name in self.FIELDS_REQUIRED.keys():
            new_ft[fld_name] = self.FIELDS_REQUIRED[fld_name]["DEFAULT_VALUE"]
        
        # regarding the additional fields, default values are used except for the pk
        else:
          if fld_name.lower() == "pk":
            new_ft[fld_name] = self.PK
            self.PK += 1
          else:
            new_ft[fld_name] = self.FIELDS_ADD[fld_name]["DEFAULT_VALUE"]
            
      sink.addFeatures([new_ft])
          
