package com.ffii.lioner.modules.lioner.template.service;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.ffii.core.exception.NotFoundException;
import com.ffii.core.exception.UnprocessableEntityException;
import com.ffii.core.support.AbstractBaseEntityService;
import com.ffii.core.support.JdbcDao;
import com.ffii.core.utils.BeanUtils;
import com.ffii.lioner.modules.common.service.AuditLogService;
import com.ffii.lioner.modules.lioner.service.FileService;
import com.ffii.lioner.modules.lioner.template.entity.Template;
import com.ffii.lioner.modules.lioner.template.entity.TemplateRepository;
import com.ffii.lioner.modules.lioner.template.req.UpdateTemplateReq;


@Service
public class TemplateService extends AbstractBaseEntityService<Template, Long, TemplateRepository> {

	private String pdf_path = "templates/pdf/"; 
    
	private AuditLogService auditLogService;
	private FileService fileService;
	
	public TemplateService(JdbcDao jdbcDao, TemplateRepository repository, AuditLogService auditLogService, FileService fileService) {
		super(jdbcDao, repository);
		this.auditLogService = auditLogService;
		this.fileService = fileService;
	}

	public Map<String, Object> saveOrUpdate(String recordJson, MultipartFile file, Boolean newUpload) {
		ObjectMapper objectMapper = new ObjectMapper();
        UpdateTemplateReq req;
        try {
            req = objectMapper.readValue(recordJson, UpdateTemplateReq.class);
        } catch (Exception e) {
            throw new UnprocessableEntityException("Invalid JSON format");
        }
		
		Template instance;
		// List<SubDivision> onUsingIdList = new ArrayList<SubDivision>();
		if(req.getId()>0){
			instance = find(req.getId()).get();
		}
		else{
			instance = new Template();
		}

		BeanUtils.copyProperties(req, instance);
		
		Map<String, Object> template = new HashMap<>();
		Map<String, Object> response = new HashMap<>();

		if (newUpload) {
			if (file.isEmpty()) {
				throw new UnprocessableEntityException("No file uploaded.");
				// return ResponseEntity.badRequest().body(Map.of("message", "No file uploaded."));
			}
			try {
				MultipartFile[] files = new MultipartFile[1];
				files[0] = file;
				
				try {
					template = fileService.saveOrUpdate(files, (long) 0, "pdf");
				} catch (Exception e) {
					System.out.println(e);
				}

				response.put("message", "Template uploaded successfully.");
				// response.put("id", pdfForm.getId().toString()); // Return the ID of the saved PDF

				if (req.getId() > 0) {
					if (fileService.existsById(instance.getFileId())) {
						fileService.deleteFile(instance.getFileId());	// Delete previous record - WIP
					}
				}

			} catch (Exception e) {
				throw new UnprocessableEntityException(
					"Failed to save PDF: "
					+ e
				);
			}
			// Link the new saved PDF to the template
			Object fileIdList = template.get("fileIdList");
			List<?> list = (List<?>) fileIdList;
			Long fileId = (long) list.get(0);
	
			instance.setFileId(fileId);
		}
		
		instance = save(instance);

		response = Map.of(
			"id", instance.getId()
		);

		return response;
	}

	// Converter -- WIP
	public File convertMultipartFileToFile(MultipartFile multipartFile) throws IOException {
        // Convert MultipartFile to byte array
        byte[] bytes = multipartFile.getBytes();

        // Create a temporary file
        File file = File.createTempFile("tempFile", multipartFile.getOriginalFilename());

        // Write byte array to the file
        try (FileOutputStream fos = new FileOutputStream(file)) {
            fos.write(bytes);
        }

        return file;
    }

	public List<Map<String,Object>> list(Map<String, Object> args){
		StringBuilder sql = new StringBuilder("SELECT"
			+ " t.id, "
			+ " t.name, "
			+ " t.remarks, "
			+ " t.fileId, "
			+ " t.created, "
			+ " t.modified, "
			+ " f.filename "
			+ " FROM template t "
			+ " LEFT JOIN file f ON f.id = t.fileId "
			+ " LEFT JOIN file_blob fb ON f.id = fb.fileId "
			+ " WHERE t.deleted = FALSE "
		);

		if (args != null) {
			if (args.containsKey("name")) 
				sql.append(" AND t.name LIKE :name ");
			if (args.containsKey("remarks")) 
				sql.append(" AND t.remarks LIKE :remarks ");
			if (args.containsKey("createDateFrom")) 
				sql.append(" AND t.created >= :createDateFrom ");
			if (args.containsKey("createDateTo")) 
				sql.append(" AND t.created <= :createDateTo ");
		}
		sql.append(" order by name like 'SL%', name like 'ML%', name like 'HSBC%' , name like 'Lioner%', name desc ");

		return jdbcDao.queryForList(sql.toString(), args);
	}

	public Map<String, Object> loadTemplate(Long id) {
		StringBuilder sql = new StringBuilder("SELECT"
			+ " t.id, "
			+ " t.name, "
			+ " t.name as templateName, "
			+ " t.remarks, "
			+ " f.filename, "
			+ " fb.bytes AS blobValue"
			+ " FROM template t "
			+ " LEFT JOIN file f ON f.id = t.fileId "
			+ " LEFT JOIN file_blob fb ON f.id = fb.fileId "
			+ " WHERE t.deleted = FALSE "
			+ " AND t.id = :id "
        );
        return jdbcDao.queryForMap(sql.toString(), Map.of("id", id)).orElseThrow(NotFoundException::new);
    }

	public Map<String, Object> loadPDF(Long id) {
		// Pdf pdfInstance = find(id).orElseThrow(NotFoundException::new);
		// byte[] blobBytes = fileService.getfileBlob(pdfInstance.getFileId());

		StringBuilder sql = new StringBuilder("SELECT"
			+ " t.*, "
			+ " fb.bytes AS blobValue"
			+ " FROM template t "
			+ " LEFT JOIN file_blob fb ON t.fileId = fb.fileId "
			+ " WHERE t.deleted = FALSE"
			+ " AND t.id = :id "
        );
        // Map<String, Object> result = jdbcDao.queryForMap(sql.toString(), Map.of("id", id)).orElseThrow(NotFoundException::new);
		// result.put("blobValue", new ByteArrayResource(blobBytes));
		// return result;
        return jdbcDao.queryForMap(sql.toString(), Map.of("id", id)).orElseThrow(NotFoundException::new);
    }

	public Map<String, Object> getPdfBlob(Long id) {
		String sql = "SELECT " +
			" fb.*, " +
			" fb.bytes AS blobValue " +
			" FROM file_blob fb " +
			" WHERE fb.deleted = FALSE " +
			" AND fb.id = :id ";
			
		return jdbcDao.queryForMap(sql, Map.of("id", id)).orElseThrow(NotFoundException::new);
    }
	
	public Integer getIdByName(String name) {
        StringBuilder sql = new StringBuilder("SELECT"
			+ " e.id "
			+ " FROM event e  "
			+ " WHERE e.deleted = FALSE"
			+ " AND e.name = :name "
        );
        
        return jdbcDao.queryForInt(sql.toString(), Map.of("name", name));
    }

}