package cz.muni.fi.pa165.microservice3.email;

import com.fasterxml.jackson.databind.ObjectMapper;
import cz.muni.fi.pa165.model.dto.house.HouseDto;
import cz.muni.fi.pa165.model.dto.user.UserDto;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.mail.MailAuthenticationException;
import org.springframework.mail.MailException;
import org.springframework.mail.MailSendException;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Arrays;
import java.util.List;

@EnableScheduling
@Service
public class EmailService {

	private final JavaMailSender javaMailSender;

	@Autowired
	public EmailService(JavaMailSender javaMailSender) {
		this.javaMailSender = javaMailSender;
	}


	public void send(EmailTemplate emailTemplate) {

		SimpleMailMessage msg = new SimpleMailMessage();
		msg.setTo(emailTemplate.getSendTo());
		msg.setSubject(emailTemplate.getSubject());
		msg.setText(emailTemplate.getBody());
		javaMailSender.send(msg);
	}

	@Scheduled(cron = "@Midnight")
	@ConditionalOnProperty(name = "emailScheduler.enabled", matchIfMissing = true)
	public void sendDailyStatisticToCustomers() {
		List<UserDto> customers;
		try {
			customers = getAllCustomers();
		} catch (IOException e) {
			LoggerFactory.getLogger(EmailService.class).error("Getting all customers failed. Error: " + e);
			return;
		}
		for (UserDto user : customers) {
			String email = user.getEmail();
			StringBuilder houseStatistics = new StringBuilder();
			List<HouseDto> houses;
			try {
				houses = getAllHousesOfUser(user.getId());
			} catch (IOException e) {
				LoggerFactory.getLogger(EmailService.class).error("Getting houses of user failed. Error: " + e);
				return;
			}
			for (HouseDto house : houses) {
				String address = house.getAddress() + " " + house.getCity() + " " + house.getZipcode() + " " + house.getState();
				String statistics;
				try {
					statistics = getDailyHouseStatistics(user.getId(), house.getId());
				} catch (IOException e) {
					LoggerFactory.getLogger(EmailService.class).error("Getting daily statistics failed. Error: " + e);
					return;
				}
				houseStatistics.append(String.format(EmailUtils.HOUSE_STATISTICS_TEMPLATE, address, statistics));
			}
			String body = String.format(EmailUtils.EMAIL_TEMPLATE, houseStatistics);
			String subject = "Daily statistics";
			try {
				send(EmailTemplate.builder().sendTo(email).subject(subject).body(body).build());
			} catch (MailAuthenticationException e) {
				LoggerFactory.getLogger(EmailService.class).error("Authentication failed. Error: " + e);
			} catch (MailSendException e) {
				LoggerFactory.getLogger(EmailService.class).error("Mail sending error:" + e);
			} catch (MailException e) {
				LoggerFactory.getLogger(EmailService.class).error("Failed to send email. Error: " + e);
			}
		}

	}

	private List<UserDto> getAllCustomers() throws IOException {
		HttpClient httpClient = HttpClientBuilder.create().build();
		HttpGet request = new HttpGet("http://localhost:8080/api/user/customers");
		request.setHeader("Content-Type", "application/json");

		HttpResponse response = httpClient.execute(request);
		String responseBody = EntityUtils.toString(response.getEntity());
		ObjectMapper objectMapper = new ObjectMapper();
		return Arrays.asList(objectMapper.readValue(responseBody, UserDto[].class));
	}

	private List<HouseDto> getAllHousesOfUser(String userId) throws IOException {
		HttpClient httpClient = HttpClientBuilder.create().build();
		HttpGet request = new HttpGet("http://localhost:8080/api/user/houses/" + userId);
		request.setHeader("Content-Type", "application/json");

		HttpResponse response = httpClient.execute(request);
		String responseBody = EntityUtils.toString(response.getEntity());
		ObjectMapper objectMapper = new ObjectMapper();
		return Arrays.asList(objectMapper.readValue(responseBody, HouseDto[].class));
	}

	private String getDailyHouseStatistics(String userId, String houseId) throws IOException {
		Instant startDateTime = LocalDateTime.now().minusDays(1).withHour(0).withMinute(0).withSecond(0).toInstant(ZoneOffset.UTC);
		Instant lastDateTime = LocalDateTime.now().minusDays(1).withHour(23).withMinute(59).withSecond(59).toInstant(ZoneOffset.UTC);

		String payload = String.format("""
						{
						    "userId": "%s",
						    "houseId": "%s",
						    "startTime": "%s",
						    "endTime": "%s"
						}
						""", userId,
				houseId,
				startDateTime,
				lastDateTime);
		StringEntity entity = new StringEntity(payload,
				ContentType.APPLICATION_JSON);

		HttpClient httpClient = HttpClientBuilder.create().build();
		HttpPost request = new HttpPost("http://localhost:8080/api/user/statistics");
		request.setEntity(entity);
		request.setHeader("Content-Type", "application/json");

		HttpResponse response = httpClient.execute(request);
		String statistics = EntityUtils.toString(response.getEntity());
		return statistics.isEmpty() ? "0" : statistics;
	}
}
