package de.cannamanage.service;

import de.cannamanage.domain.entity.*;
import de.cannamanage.domain.enums.GrowStage;
import de.cannamanage.domain.enums.SensorReadingType;
import de.cannamanage.service.repository.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.server.ResponseStatusException;

import java.math.BigDecimal;
import java.time.Instant;
import java.util.List;
import java.util.UUID;

@Slf4j
@Service
@RequiredArgsConstructor
public class GrowCalendarService {

    private final GrowEntryRepository growEntryRepository;
    private final GrowStageLogRepository growStageLogRepository;
    private final SensorReadingRepository sensorReadingRepository;
    private final GrowPhotoRepository growPhotoRepository;
    private final FeedingLogRepository feedingLogRepository;
    private final BatchRepository batchRepository;

    @Transactional(readOnly = true)
    public List<GrowEntry> getGrowEntries() {
        return growEntryRepository.findAllByOrderByStartedAtDesc();
    }

    @Transactional(readOnly = true)
    public GrowEntry getGrowEntry(UUID id) {
        return growEntryRepository.findById(id)
                .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Grow entry not found"));
    }

    @Transactional
    public GrowEntry createGrowEntry(String name, UUID strainId, String notes, Instant expectedHarvestAt) {
        GrowEntry entry = new GrowEntry();
        entry.setName(name);
        entry.setStrainId(strainId);
        entry.setStatus(GrowStage.SEEDLING);
        entry.setStartedAt(Instant.now());
        entry.setExpectedHarvestAt(expectedHarvestAt);
        entry.setNotes(notes);

        GrowEntry saved = growEntryRepository.save(entry);

        // Create initial stage log
        GrowStageLog stageLog = new GrowStageLog();
        stageLog.setGrowEntryId(saved.getId());
        stageLog.setStage(GrowStage.SEEDLING);
        stageLog.setStartedAt(Instant.now());
        growStageLogRepository.save(stageLog);

        log.debug("Created grow entry: {} with stage SEEDLING", saved.getId());
        return saved;
    }

    @Transactional
    public GrowEntry advanceStage(UUID entryId, GrowStage newStage) {
        GrowEntry entry = getGrowEntry(entryId);

        // Close the current stage log
        List<GrowStageLog> logs = growStageLogRepository.findByGrowEntryIdOrderByStartedAtAsc(entryId);
        if (!logs.isEmpty()) {
            GrowStageLog currentLog = logs.get(logs.size() - 1);
            if (currentLog.getEndedAt() == null) {
                currentLog.setEndedAt(Instant.now());
                growStageLogRepository.save(currentLog);
            }
        }

        // Create new stage log
        GrowStageLog newLog = new GrowStageLog();
        newLog.setGrowEntryId(entryId);
        newLog.setStage(newStage);
        newLog.setStartedAt(Instant.now());
        growStageLogRepository.save(newLog);

        // Update entry status
        entry.setStatus(newStage);
        log.debug("Advanced grow entry {} to stage {}", entryId, newStage);
        return growEntryRepository.save(entry);
    }

    @Transactional
    public SensorReading addSensorReading(UUID entryId, SensorReadingType type, BigDecimal value, String unit) {
        // Verify entry exists
        getGrowEntry(entryId);

        SensorReading reading = new SensorReading();
        reading.setGrowEntryId(entryId);
        reading.setReadingType(type);
        reading.setValue(value);
        reading.setUnit(unit);
        reading.setRecordedAt(Instant.now());
        return sensorReadingRepository.save(reading);
    }

    @Transactional
    public GrowPhoto addPhoto(UUID entryId, String filePath, String caption) {
        getGrowEntry(entryId);

        GrowPhoto photo = new GrowPhoto();
        photo.setGrowEntryId(entryId);
        photo.setFilePath(filePath);
        photo.setCaption(caption);
        photo.setTakenAt(Instant.now());
        return growPhotoRepository.save(photo);
    }

    @Transactional
    public FeedingLog addFeedingLog(UUID entryId, String nutrientName, BigDecimal amountMl,
                                     BigDecimal waterLiters, BigDecimal phAfter, BigDecimal ecAfter, String notes) {
        getGrowEntry(entryId);

        FeedingLog feeding = new FeedingLog();
        feeding.setGrowEntryId(entryId);
        feeding.setNutrientName(nutrientName);
        feeding.setAmountMl(amountMl);
        feeding.setWaterLiters(waterLiters);
        feeding.setPhAfter(phAfter);
        feeding.setEcAfter(ecAfter);
        feeding.setFedAt(Instant.now());
        feeding.setNotes(notes);
        return feedingLogRepository.save(feeding);
    }

    @Transactional
    public GrowEntry completeHarvest(UUID entryId, BigDecimal grams, UUID batchId) {
        GrowEntry entry = getGrowEntry(entryId);

        if (batchId != null) {
            batchRepository.findById(batchId)
                    .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Batch not found"));
            entry.setLinkedBatchId(batchId);
        }

        entry.setHarvestedGrams(grams);
        entry.setActualHarvestAt(Instant.now());
        entry.setStatus(GrowStage.COMPLETE);

        // Close stage log
        List<GrowStageLog> logs = growStageLogRepository.findByGrowEntryIdOrderByStartedAtAsc(entryId);
        if (!logs.isEmpty()) {
            GrowStageLog currentLog = logs.get(logs.size() - 1);
            if (currentLog.getEndedAt() == null) {
                currentLog.setEndedAt(Instant.now());
                growStageLogRepository.save(currentLog);
            }
        }

        // Create COMPLETE stage log
        GrowStageLog completeLog = new GrowStageLog();
        completeLog.setGrowEntryId(entryId);
        completeLog.setStage(GrowStage.COMPLETE);
        completeLog.setStartedAt(Instant.now());
        growStageLogRepository.save(completeLog);

        log.debug("Completed harvest for grow entry {}: {}g", entryId, grams);
        return growEntryRepository.save(entry);
    }

    @Transactional(readOnly = true)
    public List<GrowStageLog> getStageLogs(UUID entryId) {
        return growStageLogRepository.findByGrowEntryIdOrderByStartedAtAsc(entryId);
    }

    @Transactional(readOnly = true)
    public List<SensorReading> getSensorReadings(UUID entryId) {
        return sensorReadingRepository.findByGrowEntryIdOrderByRecordedAtDesc(entryId);
    }

    @Transactional(readOnly = true)
    public List<GrowPhoto> getPhotos(UUID entryId) {
        return growPhotoRepository.findByGrowEntryIdOrderByTakenAtDesc(entryId);
    }

    @Transactional(readOnly = true)
    public List<FeedingLog> getFeedingLogs(UUID entryId) {
        return feedingLogRepository.findByGrowEntryIdOrderByFedAtDesc(entryId);
    }
}
