package com.platform2easy.genesis.domain.service;

import com.platform2easy.genesis.domain.model.AppUser;
import com.platform2easy.genesis.domain.model.Company;
import com.platform2easy.genesis.domain.model.Wallet;
import com.platform2easy.genesis.domain.repository.AppUserRepository;
import com.platform2easy.genesis.domain.repository.CompanyRepository;
import com.platform2easy.genesis.domain.service.WalletService;
import com.platform2easy.genesis.web.dto.CompanyWithUserDTO;
import com.platform2easy.genesis.web.dto.CompanyUserResponseDTO;
import lombok.RequiredArgsConstructor;
import com.platform2easy.genesis.lib.BashExecutor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.nio.file.Paths;
import java.util.List;
import java.util.HashMap;
import java.util.Map;

@Service
@RequiredArgsConstructor
public class CompanyService {

    private final CompanyRepository repository;
    private final AppUserRepository userRepository;
    private final PasswordEncoder passwordEncoder;
    private final WalletService walletService;

    @Value("${easycli.path:}")
    private String easycliPath;

    @Value("${chain.polygon.id:1}")
    private Long defaultChainId;

    @Value("${ROOT_DIR:}")
    private String rootDir;

    @Transactional
    public Company salvar(Company company) {
        repository.save(company);
        return company;
    }

    public List<Company> listarTodos() {
        return repository.findAll();
    }

    public Company buscarPorId(Long id) {
        return repository.findById(id).orElseThrow();
    }

    public void deletarPorId(Long id) {
        repository.deleteById(id);
    }

    @Transactional
    public CompanyUserResponseDTO registerCompanyWithUser(CompanyWithUserDTO dto) {
        Company company = new Company();
        company.setName(dto.getCompanyName());
        company.setFlag("a");
        company = repository.save(company);

        AppUser user = new AppUser();
        user.setUserName(dto.getUserName());
        user.setUserEmail(dto.getUserEmail());
        user.setUserPassword(passwordEncoder.encode(dto.getUserPassword()));
        user.setUserPhone(dto.getUserPhone());
        user.setUserAddress(dto.getUserAddress());
        user.setUserCity(dto.getUserCity());
        user.setUserState(dto.getUserState());
        user.setUserZip(dto.getUserZip());
        user.setUserCountry(dto.getUserCountry());
        user.setUserKyc(dto.getUserKyc());
        user.setUserBirthdate(dto.getUserBirthdate());
        user.setUserCpf(dto.getUserCpf());
        user.setCompanyId(company.getId().intValue());
        user.setRoleId(dto.getRoleId());
        user.setUserFlag("a");
        userRepository.save(user);

        String root = (rootDir == null || rootDir.isBlank()) ? System.getenv("ROOT_DIR") : rootDir;
        String cliFullPath = (root != null && !root.isBlank())
                ? Paths.get(root).resolve("bin").resolve("easycli").toString()
                : ((easycliPath == null || easycliPath.isBlank())
                    ? Paths.get("").toAbsolutePath().resolve("bin").resolve("easycli").toString()
                    : easycliPath);
        String command = cliFullPath + " polygon create-new-address";
        BashExecutor.Result result = BashExecutor.run(command, 15000);
        if (result.isTimedOut() || result.getExitCode() != 0) {
            throw new RuntimeException("Falha ao gerar nova address via CLI: " + result.getOutput());
        }

        Map<String, String> kv = new HashMap<>();
        for (String line : result.getOutput().split("\\R")) {
            int i = line.indexOf('=');
            if (i > 0) {
                kv.put(line.substring(0, i).trim(), line.substring(i + 1).trim());
            }
        }
        String privateKey = kv.get("privateKey");
        String publicKey = kv.get("publicKey");
        String address = kv.get("address");
        if (privateKey == null || publicKey == null || address == null) {
            throw new RuntimeException("Saída da CLI inválida: " + result.getOutput());
        }

        Wallet wallet = new Wallet();
        wallet.setCompanyId(company.getId());
        wallet.setAddress(address);
        wallet.setPublicKey(publicKey);
        wallet.setPrivateKey(privateKey);
        wallet.setFlag("a");
        wallet.setChainId(defaultChainId);
        walletService.salvar(wallet);
    
        return new CompanyUserResponseDTO(
                new CompanyUserResponseDTO.CompanyId(company.getId()),
                new CompanyUserResponseDTO.UserId(user.getUserId())
        );
    }
}