package cd.casic.ci.repository.service;

import cd.casic.ci.repository.controller.admin.OpsVcsVO;
import cd.casic.ci.repository.dal.dataobject.OpsVcsDO;
import cd.casic.ci.repository.dal.mysql.RepositoryServiceMapper;
import cd.casic.ci.repository.enums.RepositoryExceptionEnum;
import cd.casic.ci.repository.exception.RepositoryException;
import cd.casic.ci.repository.util.CryptogramUtil;
import cd.casic.framework.commons.pojo.CommonResult;
import cd.casic.framework.commons.pojo.PageResult;
import cd.casic.framework.commons.util.object.BeanUtils;
import cd.casic.framework.security.core.util.SecurityFrameworkUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import jakarta.annotation.Resource;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.LsRemoteCommand;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.TransportException;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import java.util.*;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @author: Paul
 * @create: 2025-05-26 11:13
 */
@Service
@Validated
public class OpsRepositoryServiceImpl implements OpsRepositoryService {

    @Resource
    private RepositoryServiceMapper repositoryServiceMapper;


    @Override
//    @Transactional(rollbackFor = Exception.class)
    public int add(OpsVcsVO opsVcs) {
        OpsVcsDO vcsDO = BeanUtils.toBean(opsVcs, OpsVcsDO.class);
        Long tenantId = SecurityFrameworkUtils.getLoginUser().getTenantId();//获取租户id
        vcsDO.setTenantId(tenantId == null ? null : tenantId.toString());
        vcsDO.setDeptCode(SecurityFrameworkUtils.getLoginUserDeptId().toString());
        vcsDO.setVcsPassword(CryptogramUtil.doEncrypt(opsVcs.getVcsPassword())); // 加密
        return repositoryServiceMapper.insert(vcsDO);
    }

    @Override
    public Integer delete(Long opsVcsId) {
        return repositoryServiceMapper.deleteById(opsVcsId);
    }

    @Override
    public Integer edit(OpsVcsVO opsVcsVO) {
        return repositoryServiceMapper.updateById(BeanUtils.toBean(opsVcsVO, OpsVcsDO.class));
    }

    @Override
    public OpsVcsDO detail(Long opsVcsId) {
        return repositoryServiceMapper.selectById(opsVcsId);
    }

    @Override
    public List<OpsVcsDO> vcsList() {
        return repositoryServiceMapper.selectList();
    }

    @Override
    public PageResult<OpsVcsDO> getVcsPage(OpsVcsVO opsVcsVO) {
        QueryWrapper<OpsVcsDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().like(Objects.nonNull(opsVcsVO.getVcsName()), OpsVcsDO::getVcsName, opsVcsVO.getVcsName());
        queryWrapper.lambda().like(Objects.nonNull(opsVcsVO.getVscUsername()), OpsVcsDO::getVscUsername, opsVcsVO.getVscUsername());
        return repositoryServiceMapper.selectPage(opsVcsVO, queryWrapper.lambda().orderByDesc(OpsVcsDO::getCreateTime));
    }

    @Override
    public List<String> getBranch(Long opsVcsId) {
        OpsVcsDO vcs = detail(opsVcsId);
        String repositoryUrl = vcs.getVscUrl();
        String username = Optional.ofNullable(vcs.getVscUsername()).
                orElseThrow(() -> new RepositoryException(RepositoryExceptionEnum.GIT_USER_OR_PWD_IS_NONE));
        String vcsPwd = Optional.ofNullable(vcs.getVcsPassword()).
                orElseThrow(() -> new RepositoryException(RepositoryExceptionEnum.GIT_USER_OR_PWD_IS_NONE));
        // 解密
        String password = CryptogramUtil.doDecrypt(vcsPwd);
        // 创建凭证提供者(如果需要认证)
        CredentialsProvider credentialsProvider = null;
        if (username != null && password != null) {
            credentialsProvider = new UsernamePasswordCredentialsProvider(username, password);
        }
        try {
            Collection<Ref> refs = Git.lsRemoteRepository()
                    .setRemote(repositoryUrl)
                    .setCredentialsProvider(credentialsProvider)
                    .call();
            List<String> branchNames = new ArrayList<>();
            for (Ref ref : refs) {
                String refName = ref.getName();
                if (refName.startsWith("refs/heads/")) {
                    branchNames.add(refName.substring("refs/heads/".length()));
                }
            }
            return branchNames;
        } catch (GitAPIException e) {
            throw new RepositoryException(RepositoryExceptionEnum.GIT_INVALID_URL_ERROR.getMessage(), e);
        }
    }

    @Override
    public CommonResult checkVcsUrl(OpsVcsVO opsVcs) {

        String username = Optional.ofNullable(opsVcs.getVscUsername()).
                orElseThrow(() -> new RepositoryException(RepositoryExceptionEnum.GIT_USER_OR_PWD_IS_NONE));
        AtomicReference<String> passwordRef = new AtomicReference<>();
        passwordRef.set(Optional.ofNullable(opsVcs.getVcsPassword()).
                orElseThrow(() -> new RepositoryException(RepositoryExceptionEnum.GIT_USER_OR_PWD_IS_NONE)));
        Optional.ofNullable(opsVcs.getId()).ifPresent(a -> passwordRef.set(CryptogramUtil.doDecrypt(opsVcs.getVcsPassword())));
        String password = passwordRef.get();
        LsRemoteCommand lsRemoteCommand = new LsRemoteCommand(null);
        lsRemoteCommand.setRemote(opsVcs.getVscUrl());
        lsRemoteCommand.setTimeout(8); // 设置超时时间为8秒
        // 如果需要认证
        if (username != null && password != null) {
            CredentialsProvider credentialsProvider =
                    new UsernamePasswordCredentialsProvider(username, password);
            lsRemoteCommand.setCredentialsProvider(credentialsProvider);
        }
        try {
            lsRemoteCommand.call();
            return CommonResult.success(RepositoryExceptionEnum.getErrorCode(RepositoryExceptionEnum.VCS_INITIALIZED));
        } catch (TransportException e) {
            if (e.getMessage().contains("not authorized")) {
                return CommonResult.error(RepositoryExceptionEnum.getErrorCode(RepositoryExceptionEnum.VCS_UNABLE_CONNECT));
            } else if (e.getMessage().contains("Connection timed out") ||
                    e.getMessage().contains("Unable to connect")) {
                return CommonResult.error(RepositoryExceptionEnum.getErrorCode(RepositoryExceptionEnum.GIT_INVALID_URL_ERROR));
            }
            return CommonResult.error(RepositoryExceptionEnum.getErrorCode(RepositoryExceptionEnum.GIT_INVALID_URL_ERROR));
        } catch (GitAPIException e) {
            return CommonResult.error(RepositoryExceptionEnum.getErrorCode(RepositoryExceptionEnum.GIT_INVALID_URL_ERROR));
        }
    }

}
