package tv.pluto.mongo.utils.json.mongocodec;

import com.plutotv.test.lib.LogUtils;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.util.Date;
import java.util.TimeZone;
import org.bson.BsonReader;
import org.bson.BsonType;
import org.bson.BsonWriter;
import org.bson.codecs.Codec;
import org.bson.codecs.DecoderContext;
import org.bson.codecs.EncoderContext;
import org.bson.types.ObjectId;
import tv.pluto.mongo.entities.timelinespast.TimelinesPast;

public class TimelinesPastCodec implements Codec<TimelinesPast> {

  @Override
  public TimelinesPast decode(BsonReader reader, DecoderContext decoderContext) {
    TimelinesPast timelinesPast = new TimelinesPast();

    reader.readStartDocument();
    while (reader.readBsonType() != BsonType.END_OF_DOCUMENT) {
      String fieldName = reader.readName();
      switch (fieldName) {
        case "_id":
          timelinesPast.setId(readObjectIdField(reader, fieldName));
          break;
        case "episode":
          timelinesPast.setEpisode(readObjectIdField(reader, fieldName));
          break;
        case "channel":
          timelinesPast.setChannel(readObjectIdField(reader, fieldName));
          break;
        case "createdAt":
          timelinesPast.setCreatedAt(readDateField(reader, fieldName));
          //          timelinesPast.setCreatedAt(new Date(reader.readDateTime()));
          break;
        case "updatedAt":
          timelinesPast.setUpdatedAt(readDateField(reader, fieldName));
          break;
        case "start":
          timelinesPast.setStart(readDateField(reader, fieldName));
          break;
        case "stop":
          timelinesPast.setStop(readDateField(reader, fieldName));
          break;
        case "featured":
          timelinesPast.setFeatured(reader.readBoolean());
          break;
        case "manualOverrideMarker":
          timelinesPast.setManualOverrideMarker(readDateField(reader, fieldName));
          break;
        default:
          reader.skipValue(); // Skip any fields we aren't handling
          break;
      }
    }
    reader.readEndDocument();
    return timelinesPast;
  }

  @Override
  public void encode(
      BsonWriter writer, TimelinesPast timelinesPast, EncoderContext encoderContext) {
    LogUtils.logInfoMessage("No encoding implemented for TimelinesPast");
  }

  @Override
  public Class<TimelinesPast> getEncoderClass() {
    return TimelinesPast.class;
  }

  private Date readDateField(BsonReader reader, String fieldName) {
    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");

    dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
    if (reader.getCurrentBsonType() == BsonType.DATE_TIME) {
      return new Date(reader.readDateTime());
    } else if (reader.getCurrentBsonType() == BsonType.STRING) {
      // Decode BSON STRING by parsing as a date
      Instant parse = Instant.parse(reader.readString());
      return Date.from(parse);
      //        return dateFormat.parse(reader.readString());
    } else {
      throw new IllegalArgumentException(
          "Unexpected BSON type for '" + fieldName + "': " + reader.getCurrentBsonType());
    }
  }

  private String readObjectIdField(BsonReader reader, String fieldName) {
    if (reader.getCurrentBsonType() == BsonType.OBJECT_ID) {
      // Read ObjectId directly and convert to String
      return reader.readObjectId().toString();
    } else if (reader.getCurrentBsonType() == BsonType.STRING) {
      // Convert String to ObjectId if valid
      String stringValue = reader.readString();
      if (ObjectId.isValid(stringValue)) {
        return new ObjectId(stringValue).toString();
      } else {
        throw new IllegalArgumentException(
            "Invalid ObjectId format for '" + fieldName + "': " + stringValue);
      }
    } else {
      throw new IllegalArgumentException(
          "Unexpected BSON type for '" + fieldName + "': " + reader.getCurrentBsonType());
    }
  }
}
