package com.mvrent.carrental.service;

import com.mvrent.carrental.model.*;
import com.mvrent.carrental.repository.BookingRepository;
import com.mvrent.carrental.repository.CategoryRepository;
import com.mvrent.carrental.repository.DriverDocumentRepository;
import com.mvrent.carrental.repository.DriverRepository;
import com.mvrent.carrental.repository.UserRepository;
import com.mvrent.carrental.repository.VendorRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.util.List;

@Service
@RequiredArgsConstructor
public class DriverService {

    private final DriverRepository driverRepository;
    private final DriverDocumentRepository driverDocumentRepository;
    private final CategoryRepository categoryRepository;
    private final BookingRepository bookingRepository;
    private final VendorRepository vendorRepository;
    private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;

    public List<Driver> findAll() {
        return driverRepository.findAllByOrderByName();
    }

    public List<Driver> findAvailable() {
        return driverRepository.findByStatus(DriverStatus.AVAILABLE);
    }

    public Driver findById(Long id) {
        return driverRepository.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("Driver not found: " + id));
    }

    /**
     * Persist a driver from the admin form. For an existing driver the scalar
     * fields are copied onto the managed entity so its documents are preserved.
     */
    @Transactional
    public Driver saveFromForm(Driver form, Long categoryId, Long vendorId) {
        Driver target = form.getId() != null ? findById(form.getId()) : new Driver();
        target.setName(form.getName());
        target.setPhone(form.getPhone());
        target.setLicenceNumber(form.getLicenceNumber());
        target.setLicenceExpiry(form.getLicenceExpiry());
        target.setYearsExperience(form.getYearsExperience());
        target.setCategory(categoryId == null ? null
                : categoryRepository.findById(categoryId).orElse(null));
        target.setEmploymentType(form.getEmploymentType());
        target.setHourlyCharge(form.getHourlyCharge());
        target.setDailyCharge(form.getDailyCharge());
        target.setMonthlyCharge(form.getMonthlyCharge());
        target.setStatus(form.getStatus());
        target.setPhotoUrl(form.getPhotoUrl());
        // Vendor link only applies to vendor-supplied drivers.
        if (form.getEmploymentType() == DriverEmploymentType.VENDOR && vendorId != null) {
            target.setVendor(vendorRepository.findById(vendorId).orElse(null));
        } else {
            target.setVendor(null);
        }
        return driverRepository.save(target);
    }

    @Transactional
    public void delete(Long id) {
        driverRepository.deleteById(id);
    }

    /** Set a driver's availability status (used by the inline activate/deactivate toggle). */
    @Transactional
    public Driver updateStatus(Long id, DriverStatus status) {
        Driver driver = findById(id);
        driver.setStatus(status);
        return driverRepository.save(driver);
    }

    /** Create a /driver portal login linked to this driver record. */
    @Transactional
    public User createPortalUser(Long driverId, String username, String email, String rawPassword) {
        Driver driver = findById(driverId);
        if (username == null || username.isBlank()) throw new IllegalArgumentException("Username is required");
        if (email == null || email.isBlank()) throw new IllegalArgumentException("Email is required");
        if (rawPassword == null || rawPassword.length() < 6) throw new IllegalArgumentException("Password must be at least 6 characters");
        if (userRepository.existsByUsername(username.trim())) throw new IllegalArgumentException("Username already taken");
        if (userRepository.existsByEmail(email.trim())) throw new IllegalArgumentException("Email already registered");
        User user = User.builder()
                .username(username.trim())
                .email(email.trim())
                .password(passwordEncoder.encode(rawPassword))
                .fullName(driver.getName())
                .phone(driver.getPhone())
                .role(Role.DRIVER)
                .driver(driver)
                .enabled(true)
                .build();
        return userRepository.save(user);
    }

    /* ---------- Documents ---------- */

    @Transactional
    public DriverDocument addDocument(Long driverId, DriverDocumentType type, String fileUrl,
                                      LocalDate issued, LocalDate expiry) {
        Driver driver = findById(driverId);
        DriverDocument doc = DriverDocument.builder()
                .driver(driver).docType(type).fileUrl(fileUrl)
                .issuedDate(issued).expiryDate(expiry).build();
        return driverDocumentRepository.save(doc);
    }

    @Transactional
    public void deleteDocument(Long docId) {
        driverDocumentRepository.deleteById(docId);
    }

    public List<DriverDocument> documentsExpiringWithin(int days) {
        return driverDocumentRepository.findExpiringOrExpired(LocalDate.now().plusDays(days));
    }

    /* ---------- Trip history ---------- */

    public List<Booking> tripHistory(Driver driver) {
        return bookingRepository.findByDriverOrderByCreatedAtDesc(driver);
    }

    public long totalTrips(Driver driver) {
        return bookingRepository.countByDriver(driver);
    }
}
