import 'package:drift/drift.dart' hide Query;
import 'package:immich_mobile/domain/models/exif.model.dart' as domain;
import 'package:immich_mobile/infrastructure/entities/exif.entity.drift.dart';
import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.dart';
import 'package:immich_mobile/infrastructure/utils/drift_default.mixin.dart';
import 'package:immich_mobile/infrastructure/utils/exif.converter.dart';
import 'package:isar/isar.dart';

part 'exif.entity.g.dart';

/// Exif information 1:1 relation with Asset
@Collection(inheritance: false)
class ExifInfo {
  final Id? id;
  final int? fileSize;
  final DateTime? dateTimeOriginal;
  final String? timeZone;
  final String? make;
  final String? model;
  final String? lens;
  final float? f;
  final float? mm;
  final short? iso;
  final float? exposureSeconds;
  final float? lat;
  final float? long;
  final String? city;
  final String? state;
  final String? country;
  final String? description;
  final String? orientation;

  const ExifInfo({
    this.id,
    this.fileSize,
    this.dateTimeOriginal,
    this.timeZone,
    this.make,
    this.model,
    this.lens,
    this.f,
    this.mm,
    this.iso,
    this.exposureSeconds,
    this.lat,
    this.long,
    this.city,
    this.state,
    this.country,
    this.description,
    this.orientation,
  });

  static ExifInfo fromDto(domain.ExifInfo dto) => ExifInfo(
    id: dto.assetId,
    fileSize: dto.fileSize,
    dateTimeOriginal: dto.dateTimeOriginal,
    timeZone: dto.timeZone,
    make: dto.make,
    model: dto.model,
    lens: dto.lens,
    f: dto.f,
    mm: dto.mm,
    iso: dto.iso?.toInt(),
    exposureSeconds: dto.exposureSeconds,
    lat: dto.latitude,
    long: dto.longitude,
    city: dto.city,
    state: dto.state,
    country: dto.country,
    description: dto.description,
    orientation: dto.orientation,
  );

  domain.ExifInfo toDto() => domain.ExifInfo(
    assetId: id,
    fileSize: fileSize,
    description: description,
    orientation: orientation,
    timeZone: timeZone,
    dateTimeOriginal: dateTimeOriginal,
    isFlipped: ExifDtoConverter.isOrientationFlipped(orientation),
    latitude: lat,
    longitude: long,
    city: city,
    state: state,
    country: country,
    make: make,
    model: model,
    lens: lens,
    f: f,
    mm: mm,
    iso: iso?.toInt(),
    exposureSeconds: exposureSeconds,
  );
}

@TableIndex.sql('CREATE INDEX IF NOT EXISTS idx_lat_lng ON remote_exif_entity (latitude, longitude)')
class RemoteExifEntity extends Table with DriftDefaultsMixin {
  const RemoteExifEntity();

  TextColumn get assetId => text().references(RemoteAssetEntity, #id, onDelete: KeyAction.cascade)();

  TextColumn get city => text().nullable()();

  TextColumn get state => text().nullable()();

  TextColumn get country => text().nullable()();

  DateTimeColumn get dateTimeOriginal => dateTime().nullable()();

  TextColumn get description => text().nullable()();

  IntColumn get height => integer().nullable()();

  IntColumn get width => integer().nullable()();

  TextColumn get exposureTime => text().nullable()();

  RealColumn get fNumber => real().nullable()();

  IntColumn get fileSize => integer().nullable()();

  RealColumn get focalLength => real().nullable()();

  RealColumn get latitude => real().nullable()();

  RealColumn get longitude => real().nullable()();

  IntColumn get iso => integer().nullable()();

  TextColumn get make => text().nullable()();

  TextColumn get model => text().nullable()();

  TextColumn get lens => text().nullable()();

  TextColumn get orientation => text().nullable()();

  TextColumn get timeZone => text().nullable()();

  IntColumn get rating => integer().nullable()();

  TextColumn get projectionType => text().nullable()();

  @override
  Set<Column> get primaryKey => {assetId};
}

extension RemoteExifEntityDataDomainEx on RemoteExifEntityData {
  domain.ExifInfo toDto() => domain.ExifInfo(
    fileSize: fileSize,
    dateTimeOriginal: dateTimeOriginal,
    rating: rating,
    timeZone: timeZone,
    make: make,
    model: model,
    iso: iso,
    city: city,
    state: state,
    country: country,
    description: description,
    orientation: orientation,
    latitude: latitude,
    longitude: longitude,
    f: fNumber?.toDouble(),
    mm: focalLength?.toDouble(),
    lens: lens,
    isFlipped: ExifDtoConverter.isOrientationFlipped(orientation),
    exposureSeconds: ExifDtoConverter.exposureTimeToSeconds(exposureTime),
  );
}
