import 'dart:async';
import 'package:pocketbase/pocketbase.dart';
import '../../../core/api/pocketbase_client.dart';
import '../../../core/services/finance_service.dart';
import '../../../core/services/job_history_service.dart';
import '../../../models/job.dart';

const _listExpand = 'clinic_tenant_id,lab_tenant_id,patient_id';
const _detailExpand = 'clinic_tenant_id,lab_tenant_id,patient_id,prosthetic_id';

class LabJobsRepository {
  LabJobsRepository._();
  static final instance = LabJobsRepository._();

  PocketBase get _pb => PocketBaseClient.instance.pb;

  Future<List<Job>> listInbound(
    String labTenantId, {
    String? status,
    int page = 1,
    int limit = 30,
  }) async {
    final filterParts = ['lab_tenant_id = "$labTenantId"'];
    if (status != null) filterParts.add('status = "$status"');

    final result = await _pb.collection('jobs').getList(
          page: page,
          perPage: limit,
          filter: filterParts.join(' && '),
          expand: _listExpand,
          sort: '-created',
        );
    return (result.items.map((r) => Job.fromJson(r.toJson())).toList()
      ..sort((a, b) => b.dateCreated.compareTo(a.dateCreated)));
  }

  Future<List<Job>> listInProgress(String labTenantId,
      {int limit = 50, String? location}) async {
    final filterParts = [
      'lab_tenant_id = "$labTenantId"',
      'status = "in_progress"'
    ];
    if (location != null) filterParts.add('location = "$location"');
    final result = await _pb.collection('jobs').getList(
          perPage: limit,
          filter: filterParts.join(' && '),
          expand: _listExpand,
          sort: location == null ? '-created' : null,
        );
    return (result.items.map((r) => Job.fromJson(r.toJson())).toList()
      ..sort((a, b) {
        if (a.dueDate == null && b.dueDate == null) {
          return b.dateCreated.compareTo(a.dateCreated);
        }
        if (a.dueDate == null) return 1;
        if (b.dueDate == null) return -1;
        final cmp = a.dueDate!.compareTo(b.dueDate!);
        return cmp != 0 ? cmp : b.dateCreated.compareTo(a.dateCreated);
      }));
  }

  Future<Job> getJob(String jobId) async {
    final record =
        await _pb.collection('jobs').getOne(jobId, expand: _detailExpand);
    return Job.fromJson(record.toJson());
  }

  Future<Job> acceptJob(Job pendingJob) async {
    final firstStep = pendingJob.stepTemplate.first;
    final record = await _pb.collection('jobs').update(pendingJob.id, body: {
      'status': 'in_progress',
      'current_step': firstStep.value,
      'location': 'at_lab',
    });
    final job = Job.fromJson(record.toJson());
    unawaited(JobHistoryService.instance.append(
      jobId: pendingJob.id,
      clinicTenantId: job.clinicTenantId,
      labTenantId: job.labTenantId,
      action: JobHistoryAction.accepted,
      step: firstStep,
    ));
    return job;
  }

  Future<Job> handToClinic(String jobId, Job job, {String? note}) async {
    final currentStep = job.currentStep;
    if (currentStep == null) {
      throw Exception('Geçerli bir iş adımı bulunamadı.');
    }

    final isFinal = currentStep == JobStep.cilaBitim;
    final nextStep = job.nextStep;
    final shouldStayAtLabAfterMeasure = !job.provaRequired &&
        currentStep == JobStep.olcuKontrol &&
        nextStep == JobStep.cilaBitim;
    final patch = isFinal
        ? {'status': 'sent', 'location': 'at_clinic'}
        : currentStep.requiresClinicApproval && !shouldStayAtLabAfterMeasure
            ? {'location': 'at_clinic'}
            : {
                'current_step': nextStep?.value,
                'location': 'at_lab',
              };

    final record = await _pb.collection('jobs').update(jobId, body: patch);
    final updated = Job.fromJson(record.toJson());
    unawaited(JobHistoryService.instance.append(
      jobId: jobId,
      clinicTenantId: job.clinicTenantId,
      labTenantId: job.labTenantId,
      action: (currentStep.requiresClinicApproval &&
                  !shouldStayAtLabAfterMeasure) ||
              isFinal
          ? JobHistoryAction.handedToClinic
          : JobHistoryAction.stepCompleted,
      step: currentStep,
      note: note,
    ));
    return updated;
  }

  Future<Job> cancelJob(String jobId, Job job) async {
    final record = await _pb.collection('jobs').update(jobId, body: {
      'status': 'cancelled',
    });
    await FinanceService.instance.deletePendingEntriesForJob(jobId);
    unawaited(JobHistoryService.instance.append(
      jobId: jobId,
      clinicTenantId: job.clinicTenantId,
      labTenantId: job.labTenantId,
      action: JobHistoryAction.cancelled,
      step: job.currentStep,
    ));
    return Job.fromJson(record.toJson());
  }

  Future<void> bulkAcceptPending(String labTenantId) async {
    final pending =
        await listInbound(labTenantId, status: 'pending', limit: 200);
    await Future.wait(pending.map((j) => acceptJob(j)));
  }

  Future<int> countByStatus(String labTenantId, String? status) async {
    final filter = status != null
        ? 'lab_tenant_id = "$labTenantId" && status = "$status"'
        : 'lab_tenant_id = "$labTenantId"';
    final r = await _pb.collection('jobs').getList(perPage: 1, filter: filter);
    return r.totalItems;
  }

  Future<int> countDelivered(String labTenantId,
      {DateTime? from, DateTime? to}) async {
    final parts = ['lab_tenant_id = "$labTenantId"', 'status = "delivered"'];
    if (from != null) parts.add('updated >= "${_date(from)}"');
    if (to != null) parts.add('updated < "${_date(to)}"');
    final r = await _pb
        .collection('jobs')
        .getList(perPage: 1, filter: parts.join(' && '));
    return r.totalItems;
  }

  static String _date(DateTime d) => d.toIso8601String().split('T').first;
}
