enum JobStatus { pending, inProgress, sent, delivered, cancelled }

enum JobStep {
  olcu,           // legacy fallback
  altYapiProva,   // sabit seramik/metal — alt yapı (coping)
  ustYapiProva,   // sabit seramik — bisküvi prova
  mumProva,       // hareketli protez — mum prova
  dislerProva,    // hareketli protez — dişler prova
  dayanakProva,   // implant — dayanak prova
  kronProva,      // implant — kron prova
  cilaBitim,      // son cila / bitim (her şablonda son adım)
}

enum JobLocation { atClinic, atLab }

enum JobWorkflowType { arjinat, geleneksel, dijital }

enum ProstheticType {
  metalPorselen,
  zirkonyum,
  implantUstuZirkonyum,
  gecici,
  eMax,
  tamProtez,
  parsiyel,
  diger,
}

// ── Status ────────────────────────────────────────────────────────────────────

extension JobStatusExt on JobStatus {
  String get label => switch (this) {
        JobStatus.pending    => 'Bekliyor',
        JobStatus.inProgress => 'İşlemde',
        JobStatus.sent       => 'Gönderildi',
        JobStatus.delivered  => 'Teslim Alındı',
        JobStatus.cancelled  => 'İptal',
      };
  String get value => switch (this) {
        JobStatus.pending    => 'pending',
        JobStatus.inProgress => 'in_progress',
        JobStatus.sent       => 'sent',
        JobStatus.delivered  => 'delivered',
        JobStatus.cancelled  => 'cancelled',
      };
}

// ── Step ──────────────────────────────────────────────────────────────────────

extension JobStepExt on JobStep {
  String get label => switch (this) {
        JobStep.olcu         => 'Ölçü',
        JobStep.altYapiProva => 'Alt Yapı Prova',
        JobStep.ustYapiProva => 'Üst Yapı Prova',
        JobStep.mumProva     => 'Mum Prova',
        JobStep.dislerProva  => 'Dişler Prova',
        JobStep.dayanakProva => 'Dayanak Prova',
        JobStep.kronProva    => 'Kron Prova',
        JobStep.cilaBitim    => 'Cila / Bitim',
      };

  /// One-liner shown under the step on the stepper
  String get description => switch (this) {
        JobStep.olcu         => 'İlk ölçü alındı',
        JobStep.altYapiProva => 'Metal/zirkonyum coping klinik onayı',
        JobStep.ustYapiProva => 'Bisküvi pişirimi sonrası klinik onayı',
        JobStep.mumProva     => 'Mum prova klinik onayı',
        JobStep.dislerProva  => 'Diş dizimi klinik onayı',
        JobStep.dayanakProva => 'Dayanak klinik onayı',
        JobStep.kronProva    => 'Kron klinik onayı',
        JobStep.cilaBitim    => 'Son cila ve teslim hazırlığı',
      };

  String get value => switch (this) {
        JobStep.olcu         => 'olcu',
        JobStep.altYapiProva => 'alt_yapi_prova',
        JobStep.ustYapiProva => 'ust_yapi_prova',
        JobStep.mumProva     => 'mum_prova',
        JobStep.dislerProva  => 'disler_prova',
        JobStep.dayanakProva => 'dayanak_prova',
        JobStep.kronProva    => 'kron_prova',
        JobStep.cilaBitim    => 'cila_bitim',
      };
}

extension JobWorkflowTypeExt on JobWorkflowType {
  String get label => switch (this) {
        JobWorkflowType.arjinat => 'Arjinat',
        JobWorkflowType.geleneksel => 'Geleneksel',
        JobWorkflowType.dijital => 'Dijital',
      };

  String get value => switch (this) {
        JobWorkflowType.arjinat => 'arjinat',
        JobWorkflowType.geleneksel => 'geleneksel',
        JobWorkflowType.dijital => 'dijital',
      };
}

// ── Prosthetic type ───────────────────────────────────────────────────────────

extension ProstheticTypeExt on ProstheticType {
  String get label => switch (this) {
        ProstheticType.metalPorselen        => 'Metal Porselen',
        ProstheticType.zirkonyum            => 'Zirkonyum',
        ProstheticType.implantUstuZirkonyum => 'İmplant Üstü Zirkonyum',
        ProstheticType.gecici               => 'Geçici',
        ProstheticType.eMax                 => 'E-Max',
        ProstheticType.tamProtez            => 'Tam Protez',
        ProstheticType.parsiyel             => 'Parsiyel Protez',
        ProstheticType.diger                => 'Diğer',
      };
  String get value => switch (this) {
        ProstheticType.metalPorselen        => 'metal_porselen',
        ProstheticType.zirkonyum            => 'zirkonyum',
        ProstheticType.implantUstuZirkonyum => 'implant_ustu_zirkonyum',
        ProstheticType.gecici               => 'gecici',
        ProstheticType.eMax                 => 'e_max',
        ProstheticType.tamProtez            => 'tam_protez',
        ProstheticType.parsiyel             => 'parsiyel',
        ProstheticType.diger                => 'diger',
      };
}

// ── Step template ─────────────────────────────────────────────────────────────

/// Returns the ordered step list for a given prosthetic type + prova flag.
List<JobStep> jobStepTemplate(ProstheticType type, bool provaRequired) {
  if (!provaRequired) return const [JobStep.cilaBitim];
  return switch (type) {
    // Sabit seramik: alt yapı coping + bisküvi prova + cila
    ProstheticType.metalPorselen ||
    ProstheticType.zirkonyum ||
    ProstheticType.eMax =>
        const [JobStep.altYapiProva, JobStep.ustYapiProva, JobStep.cilaBitim],
    // İmplant: dayanak + kron prova + cila
    ProstheticType.implantUstuZirkonyum =>
        const [JobStep.dayanakProva, JobStep.kronProva, JobStep.cilaBitim],
    // Hareketli protez: mum + dişler prova + cila
    ProstheticType.tamProtez ||
    ProstheticType.parsiyel =>
        const [JobStep.mumProva, JobStep.dislerProva, JobStep.cilaBitim],
    // Geçici: sadece cila (prova gereksiz)
    ProstheticType.gecici =>
        const [JobStep.cilaBitim],
    // Diğer: tek ara prova + cila
    _ =>
        const [JobStep.altYapiProva, JobStep.cilaBitim],
  };
}

// ── Job ───────────────────────────────────────────────────────────────────────

class Job {
  const Job({
    required this.id,
    required this.clinicTenantId,
    required this.labTenantId,
    required this.patientCode,
    required this.prostheticType,
    required this.memberCount,
    required this.status,
    required this.dateCreated,
    this.patientId,
    this.patientName,
    this.prostheticId,
    this.prostheticName,
    this.teeth = const [],
    this.color,
    this.description,
    this.price,
    this.currency,
    this.currentStep,
    this.location = JobLocation.atClinic,
    this.workflowType,
    this.dueDate,
    this.clinicName,
    this.labName,
    this.attachments = const [],
    this.provaRequired = true,
  });

  final String id;
  final String clinicTenantId;
  final String labTenantId;
  final String? patientId;
  final String? patientName;
  final String patientCode;
  final String? prostheticId;
  final String? prostheticName;
  final ProstheticType prostheticType;
  final int memberCount;
  final List<String> teeth;
  final String? color;
  final String? description;
  final double? price;
  final String? currency;
  final JobStatus status;
  final JobStep? currentStep;
  final JobLocation location;
  final JobWorkflowType? workflowType;
  final DateTime? dueDate;
  final DateTime dateCreated;
  final List<String> attachments;
  final bool provaRequired;

  // Denormalized from relation joins — list views only
  final String? clinicName;
  final String? labName;

  // ── copyWith ──────────────────────────────────────────────────────────────

  Job copyWith({
    JobStatus? status,
    JobStep? currentStep,
    JobLocation? location,
    JobWorkflowType? workflowType,
    String? clinicName,
    String? labName,
    bool clearCurrentStep = false,
  }) =>
      Job(
        id: id,
        clinicTenantId: clinicTenantId,
        labTenantId: labTenantId,
        patientId: patientId,
        patientName: patientName,
        patientCode: patientCode,
        prostheticId: prostheticId,
        prostheticName: prostheticName,
        prostheticType: prostheticType,
        memberCount: memberCount,
        teeth: teeth,
        color: color,
        description: description,
        price: price,
        currency: currency,
        status: status ?? this.status,
        currentStep: clearCurrentStep ? null : (currentStep ?? this.currentStep),
        location: location ?? this.location,
        workflowType: workflowType ?? this.workflowType,
        dueDate: dueDate,
        dateCreated: dateCreated,
        attachments: attachments,
        provaRequired: provaRequired,
        clinicName: clinicName ?? this.clinicName,
        labName: labName ?? this.labName,
      );

  // ── Step helpers ──────────────────────────────────────────────────────────

  List<JobStep> get stepTemplate => jobStepTemplate(prostheticType, provaRequired);

  bool get isLastStep =>
      currentStep != null && currentStep == stepTemplate.last;

  /// The next step after currentStep in this job's template, or null if done.
  JobStep? get nextStep {
    if (currentStep == null) return stepTemplate.firstOrNull;
    final idx = stepTemplate.indexOf(currentStep!);
    if (idx < 0 || idx >= stepTemplate.length - 1) return null;
    return stepTemplate[idx + 1];
  }

  factory Job.fromJson(Map<String, dynamic> j) {
    final expand = j['expand'] as Map<String, dynamic>?;
    final clinicExp = expand?['clinic_tenant_id'] as Map<String, dynamic>?;
    final labExp = expand?['lab_tenant_id'] as Map<String, dynamic>?;
    final patientExp = expand?['patient_id'] as Map<String, dynamic>?;
    final prostheticExp = expand?['prosthetic_id'] as Map<String, dynamic>?;
    String? str(dynamic v) {
      final s = v as String?;
      return (s == null || s.isEmpty) ? null : s;
    }

    return Job(
      id: j['id'] as String,
      clinicTenantId: j['clinic_tenant_id'] as String,
      labTenantId: j['lab_tenant_id'] as String,
      patientId: str(j['patient_id']),
      patientName: _patientName(patientExp),
      patientCode: j['patient_code'] as String,
      prostheticId: str(j['prosthetic_id']),
      prostheticName: prostheticExp?['name'] as String?,
      prostheticType: _parseProstheticType(j['prosthetic_type'] as String),
      memberCount: (j['member_count'] as num).toInt(),
      teeth: j['teeth'] is List
          ? (j['teeth'] as List).map((e) => e.toString()).toList()
          : [],
      color: str(j['color']),
      description: str(j['description']),
      price: (j['price'] as num?)?.toDouble(),
      currency: str(j['currency']),
      status: _parseStatus(j['status'] as String),
      currentStep: str(j['current_step']) != null
          ? _parseStep(j['current_step'] as String)
          : null,
      location:
          j['location'] == 'at_lab' ? JobLocation.atLab : JobLocation.atClinic,
      workflowType: str(j['workflow_type']) != null
          ? _parseWorkflowType(j['workflow_type'] as String)
          : null,
      dueDate: str(j['due_date']) != null
          ? DateTime.parse(j['due_date'] as String)
          : null,
      dateCreated: DateTime.parse(j['created'] as String),
      clinicName: clinicExp?['company_name'] as String?,
      labName: labExp?['company_name'] as String?,
      attachments: j['attachments'] is List
          ? (j['attachments'] as List).map((e) => e.toString()).toList()
          : [],
      provaRequired: (j['prova_required'] as bool?) ?? true,
    );
  }

  static JobStatus _parseStatus(String s) => switch (s) {
        'in_progress' => JobStatus.inProgress,
        'sent'        => JobStatus.sent,
        'delivered'   => JobStatus.delivered,
        'cancelled'   => JobStatus.cancelled,
        _             => JobStatus.pending,
      };

  static JobStep _parseStep(String s) => switch (s) {
        'alt_yapi_prova' => JobStep.altYapiProva,
        'ust_yapi_prova' => JobStep.ustYapiProva,
        'mum_prova'      => JobStep.mumProva,
        'disler_prova'   => JobStep.dislerProva,
        'dayanak_prova'  => JobStep.dayanakProva,
        'kron_prova'     => JobStep.kronProva,
        'cila_bitim'     => JobStep.cilaBitim,
        _                => JobStep.olcu,
      };

  static JobWorkflowType _parseWorkflowType(String s) => switch (s) {
        'arjinat' => JobWorkflowType.arjinat,
        'dijital' => JobWorkflowType.dijital,
        _ => JobWorkflowType.geleneksel,
      };

  static String? _patientName(Map<String, dynamic>? patientExp) {
    if (patientExp == null) return null;
    final first = (patientExp['first_name'] as String?)?.trim();
    final last = (patientExp['last_name'] as String?)?.trim();
    final parts = [first, last]
        .where((part) => part != null && part.isNotEmpty)
        .cast<String>()
        .toList();
    if (parts.isNotEmpty) return parts.join(' ');
    final code = (patientExp['patient_code'] as String?)?.trim();
    return (code == null || code.isEmpty) ? null : code;
  }

  static ProstheticType _parseProstheticType(String s) => switch (s) {
        'zirkonyum'             => ProstheticType.zirkonyum,
        'implant_ustu_zirkonyum'=> ProstheticType.implantUstuZirkonyum,
        'gecici'                => ProstheticType.gecici,
        'e_max'                 => ProstheticType.eMax,
        'tam_protez'            => ProstheticType.tamProtez,
        'parsiyel'              => ProstheticType.parsiyel,
        'diger'                 => ProstheticType.diger,
        _                       => ProstheticType.metalPorselen,
      };
}
