package com.erp.invoice.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.erp.invoice.dto.InvoiceRequest;
import com.erp.invoice.dto.InvoiceResponse;
import com.erp.invoice.entity.Invoice;
import com.erp.invoice.entity.InvoiceItem;
import com.erp.invoice.exception.InvoiceException;
import com.erp.invoice.repository.InvoiceItemRepository;
import com.erp.invoice.repository.InvoiceRepository;
import com.erp.invoice.service.InvoiceService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 发票服务实现
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class InvoiceServiceImpl extends ServiceImpl<InvoiceRepository, Invoice> implements InvoiceService {
    
    private final InvoiceRepository invoiceRepository;
    private final InvoiceItemRepository invoiceItemRepository;
    
    // ==================== CRUD操作 ====================
    
    @Override
    public Map<String, Object> listInvoices(Long tenantId, Integer status, Integer invoiceType,
                                             String keyword, LocalDate startDate, LocalDate endDate,
                                             Integer page, Integer size) {
        LambdaQueryWrapper<Invoice> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.isNull(Invoice::getDeletedAt);
        
        if (tenantId != null) {
            queryWrapper.eq(Invoice::getTenantId, tenantId);
        }
        
        if (status != null) {
            queryWrapper.eq(Invoice::getStatus, status);
        }
        
        if (invoiceType != null) {
            queryWrapper.eq(Invoice::getInvoiceType, invoiceType);
        }
        
        if (StringUtils.hasText(keyword)) {
            queryWrapper.and(w -> w.like(Invoice::getInvoiceNo, keyword)
                    .or().like(Invoice::getBuyerName, keyword)
                    .or().like(Invoice::getOrderNo, keyword));
        }
        
        if (startDate != null) {
            queryWrapper.ge(Invoice::getApplyDate, startDate);
        }
        
        if (endDate != null) {
            queryWrapper.le(Invoice::getApplyDate, endDate);
        }
        
        queryWrapper.orderByDesc(Invoice::getCreatedAt);
        
        IPage<Invoice> pageResult = invoiceRepository.selectPage(
                new Page<>(page, size), queryWrapper);
        
        List<InvoiceResponse> records = pageResult.getRecords().stream()
                .map(InvoiceResponse::fromEntity)
                .collect(Collectors.toList());
        
        Map<String, Object> result = new HashMap<>();
        result.put("list", records);
        result.put("total", pageResult.getTotal());
        result.put("current_page", pageResult.getCurrent());
        result.put("last_page", pageResult.getPages());
        result.put("page_size", pageResult.getSize());
        
        return result;
    }
    
    @Override
    public InvoiceResponse getInvoiceById(Long id) {
        Invoice invoice = invoiceRepository.selectById(id);
        if (invoice == null || invoice.getDeletedAt() != null) {
            throw new InvoiceException("发票不存在");
        }
        
        InvoiceResponse response = InvoiceResponse.fromEntity(invoice);
        response.setItems(getInvoiceItems(id));
        return response;
    }
    
    @Override
    public InvoiceResponse getInvoiceByInvoiceNo(String invoiceNo) {
        Invoice invoice = invoiceRepository.findByInvoiceNo(invoiceNo);
        if (invoice == null) {
            throw new InvoiceException("发票不存在: " + invoiceNo);
        }
        
        InvoiceResponse response = InvoiceResponse.fromEntity(invoice);
        response.setItems(getInvoiceItems(invoice.getId()));
        return response;
    }
    
    // ==================== 发票申请 ====================
    
    @Override
    @Transactional
    public InvoiceResponse createInvoice(InvoiceRequest request, Long applicantId, String applicantName) {
        Invoice invoice = new Invoice();
        invoice.setTenantId(1L); // TODO: 从上下文获取
        invoice.setInvoiceType(request.getInvoiceType());
        invoice.setStatus(Invoice.STATUS_PENDING);
        invoice.setBuyerName(request.getBuyerName());
        invoice.setBuyerTaxNo(request.getBuyerTaxNo());
        invoice.setBuyerAddressPhone(request.getBuyerAddressPhone());
        invoice.setBuyerBankAccount(request.getBuyerBankAccount());
        invoice.setTotalAmount(request.getTotalAmount());
        invoice.setAmount(request.getAmount());
        invoice.setTaxAmount(request.getTaxAmount());
        invoice.setTaxRate(request.getTaxRate());
        invoice.setOrderId(request.getOrderId());
        invoice.setOrderNo(request.getOrderNo());
        invoice.setCustomerId(request.getCustomerId());
        invoice.setCustomerName(request.getCustomerName());
        invoice.setInvoiceContent(request.getInvoiceContent());
        invoice.setRemark(request.getRemark());
        invoice.setApplyDate(LocalDate.now());
        invoice.setApplicantId(applicantId);
        invoice.setApplicantName(applicantName);
        
        invoiceRepository.insert(invoice);
        log.info("发票申请创建成功: id={}, applicant={}", invoice.getId(), applicantName);
        
        // 添加发票明细
        if (request.getItems() != null && !request.getItems().isEmpty()) {
            addInvoiceItems(invoice.getId(), request.getItems());
        }
        
        return getInvoiceById(invoice.getId());
    }
    
    @Override
    @Transactional
    public InvoiceResponse updateInvoice(Long id, InvoiceRequest request) {
        Invoice invoice = getInvoiceByIdInternal(id);
        
        // 仅允许更新待审核状态的发票
        if (!Invoice.STATUS_PENDING.equals(invoice.getStatus())) {
            throw new InvoiceException("仅允许更新待审核状态的发票");
        }
        
        invoice.setInvoiceType(request.getInvoiceType());
        invoice.setBuyerName(request.getBuyerName());
        invoice.setBuyerTaxNo(request.getBuyerTaxNo());
        invoice.setBuyerAddressPhone(request.getBuyerAddressPhone());
        invoice.setBuyerBankAccount(request.getBuyerBankAccount());
        invoice.setTotalAmount(request.getTotalAmount());
        invoice.setAmount(request.getAmount());
        invoice.setTaxAmount(request.getTaxAmount());
        invoice.setTaxRate(request.getTaxRate());
        invoice.setOrderId(request.getOrderId());
        invoice.setOrderNo(request.getOrderNo());
        invoice.setCustomerId(request.getCustomerId());
        invoice.setCustomerName(request.getCustomerName());
        invoice.setInvoiceContent(request.getInvoiceContent());
        invoice.setRemark(request.getRemark());
        
        invoiceRepository.updateById(invoice);
        log.info("发票申请更新成功: id={}", id);
        
        // 更新发票明细
        if (request.getItems() != null) {
            deleteInvoiceItems(id);
            if (!request.getItems().isEmpty()) {
                addInvoiceItems(id, request.getItems());
            }
        }
        
        return getInvoiceById(id);
    }
    
    @Override
    @Transactional
    public void deleteInvoice(Long id) {
        Invoice invoice = getInvoiceByIdInternal(id);
        
        if (!Invoice.STATUS_PENDING.equals(invoice.getStatus())) {
            throw new InvoiceException("仅允许删除待审核状态的发票");
        }
        
        deleteInvoiceItems(id);
        invoiceRepository.deleteById(id);
        log.info("发票申请删除成功: id={}", id);
    }
    
    // ==================== 发票审核 ====================
    
    @Override
    @Transactional
    public InvoiceResponse auditInvoice(Long id, Integer auditStatus, Long auditorId, String auditorName, String auditRemark) {
        Invoice invoice = getInvoiceByIdInternal(id);
        
        if (!Invoice.STATUS_PENDING.equals(invoice.getStatus())) {
            throw new InvoiceException("仅允许审核待审核状态的发票");
        }
        
        if (auditStatus != 1) {
            // 审核不通过，标记为已作废
            invoice.setStatus(Invoice.STATUS_VOIDED);
            invoice.setVoidReason(auditRemark);
            invoice.setVoidDate(LocalDate.now());
        }
        
        invoice.setAuditorId(auditorId);
        invoice.setAuditorName(auditorName);
        invoice.setRemark(invoice.getRemark() + " [审核备注: " + auditRemark + "]");
        
        invoiceRepository.updateById(invoice);
        log.info("发票审核完成: id={}, status={}, auditor={}", id, auditStatus, auditorName);
        
        return getInvoiceById(id);
    }
    
    // ==================== 发票开具 ====================
    
    @Override
    @Transactional
    public InvoiceResponse issueInvoice(Long id, String invoiceNo, String invoiceCode, LocalDate invoiceDate,
                                        Long issuerId, String issuerName, String drawer, String reviewer, String payee) {
        Invoice invoice = getInvoiceByIdInternal(id);
        
        if (!Invoice.STATUS_PENDING.equals(invoice.getStatus())) {
            throw new InvoiceException("仅允许开具待审核状态的发票，当前状态: " + invoice.getStatusName());
        }
        
        // 检查发票号是否已存在
        if (StringUtils.hasText(invoiceNo)) {
            Invoice existing = invoiceRepository.findByInvoiceNo(invoiceNo);
            if (existing != null && !existing.getId().equals(id)) {
                throw new InvoiceException("发票号码已存在: " + invoiceNo);
            }
        }
        
        invoice.setStatus(Invoice.STATUS_ISSUED);
        invoice.setInvoiceNo(invoiceNo);
        invoice.setInvoiceCode(invoiceCode);
        invoice.setInvoiceDate(invoiceDate);
        invoice.setIssuerId(issuerId);
        invoice.setIssuerName(issuerName);
        invoice.setDrawer(drawer);
        invoice.setReviewer(reviewer);
        invoice.setPayee(payee);
        
        invoiceRepository.updateById(invoice);
        log.info("发票开具成功: id={}, invoiceNo={}, issuer={}", id, invoiceNo, issuerName);
        
        return getInvoiceById(id);
    }
    
    // ==================== 发票作废/红冲 ====================
    
    @Override
    @Transactional
    public InvoiceResponse voidInvoice(Long id, String reason, Long operatorId, String operatorName) {
        Invoice invoice = getInvoiceByIdInternal(id);
        
        if (!invoice.canBeVoided()) {
            throw new InvoiceException("仅允许作废已开具状态的发票");
        }
        
        invoice.setStatus(Invoice.STATUS_VOIDED);
        invoice.setVoidReason(reason);
        invoice.setVoidDate(LocalDate.now());
        
        invoiceRepository.updateById(invoice);
        log.info("发票作废成功: id={}, reason={}, operator={}", id, reason, operatorName);
        
        return getInvoiceById(id);
    }
    
    @Override
    @Transactional
    public InvoiceResponse reverseInvoice(Long id, String reason, Long operatorId, String operatorName) {
        Invoice invoice = getInvoiceByIdInternal(id);
        
        if (!invoice.canBeReversed()) {
            throw new InvoiceException("仅允许红冲已开具状态的发票");
        }
        
        invoice.setStatus(Invoice.STATUS_REVERSED);
        invoice.setVoidReason(reason);
        invoice.setVoidDate(LocalDate.now());
        
        invoiceRepository.updateById(invoice);
        log.info("发票红冲成功: id={}, reason={}, operator={}", id, reason, operatorName);
        
        return getInvoiceById(id);
    }
    
    // ==================== 发票查询 ====================
    
    @Override
    public List<InvoiceResponse> getInvoicesByOrderId(Long orderId) {
        List<Invoice> invoices = invoiceRepository.findByOrderId(orderId);
        return invoices.stream()
                .map(InvoiceResponse::fromEntity)
                .collect(Collectors.toList());
    }
    
    @Override
    public List<InvoiceResponse> getInvoicesByCustomerId(Long customerId) {
        List<Invoice> invoices = invoiceRepository.findByCustomerId(customerId);
        return invoices.stream()
                .map(InvoiceResponse::fromEntity)
                .collect(Collectors.toList());
    }
    
    @Override
    public BigDecimal getIssuedAmountByTenant(Long tenantId) {
        return invoiceRepository.sumIssuedAmountByTenant(tenantId);
    }
    
    @Override
    public Integer countInvoicesByDateRange(Long tenantId, LocalDate startDate, LocalDate endDate) {
        return invoiceRepository.countByDateRange(tenantId, startDate, endDate);
    }
    
    // ==================== 发票文件 ====================
    
    @Override
    @Transactional
    public InvoiceResponse updatePdfPath(Long id, String pdfPath) {
        Invoice invoice = getInvoiceByIdInternal(id);
        invoice.setPdfPath(pdfPath);
        invoiceRepository.updateById(invoice);
        return getInvoiceById(id);
    }
    
    @Override
    @Transactional
    public InvoiceResponse updateImagePath(Long id, String imagePath) {
        Invoice invoice = getInvoiceByIdInternal(id);
        invoice.setImagePath(imagePath);
        invoiceRepository.updateById(invoice);
        return getInvoiceById(id);
    }
    
    // ==================== 发票明细 ====================
    
    @Override
    @Transactional
    public void addInvoiceItems(Long invoiceId, List<InvoiceRequest.InvoiceItemRequest> items) {
        for (InvoiceRequest.InvoiceItemRequest itemRequest : items) {
            InvoiceItem item = new InvoiceItem();
            item.setInvoiceId(invoiceId);
            item.setTenantId(1L); // TODO: 从上下文获取
            item.setGoodsName(itemRequest.getGoodsName());
            item.setSpec(itemRequest.getSpec());
            item.setUnit(itemRequest.getUnit());
            item.setQuantity(itemRequest.getQuantity());
            item.setUnitPrice(itemRequest.getUnitPrice());
            item.setAmount(itemRequest.getAmount());
            item.setTaxRate(itemRequest.getTaxRate());
            item.setTaxAmount(itemRequest.getTaxAmount());
            item.setTotalAmount(itemRequest.getTotalAmount());
            item.setGoodsCode(itemRequest.getGoodsCode());
            item.setTaxClassificationCode(itemRequest.getTaxClassificationCode());
            item.setPreferentialFlag(itemRequest.getPreferentialFlag());
            item.setZeroTaxFlag(itemRequest.getZeroTaxFlag());
            invoiceItemRepository.insert(item);
        }
    }
    
    @Override
    public List<InvoiceResponse.InvoiceItemResponse> getInvoiceItems(Long invoiceId) {
        List<InvoiceItem> items = invoiceItemRepository.findByInvoiceId(invoiceId);
        return items.stream().map(item -> {
            InvoiceResponse.InvoiceItemResponse response = new InvoiceResponse.InvoiceItemResponse();
            response.setId(item.getId());
            response.setInvoiceId(item.getInvoiceId());
            response.setGoodsName(item.getGoodsName());
            response.setSpec(item.getSpec());
            response.setUnit(item.getUnit());
            response.setQuantity(item.getQuantity());
            response.setUnitPrice(item.getUnitPrice());
            response.setAmount(item.getAmount());
            response.setTaxRate(item.getTaxRate());
            response.setTaxAmount(item.getTaxAmount());
            response.setTotalAmount(item.getTotalAmount());
            response.setGoodsCode(item.getGoodsCode());
            response.setTaxClassificationCode(item.getTaxClassificationCode());
            response.setPreferentialFlag(item.getPreferentialFlag());
            response.setZeroTaxFlag(item.getZeroTaxFlag());
            return response;
        }).collect(Collectors.toList());
    }
    
    @Override
    @Transactional
    public void deleteInvoiceItems(Long invoiceId) {
        invoiceItemRepository.deleteByInvoiceId(invoiceId);
    }
    
    // ==================== 私有方法 ====================
    
    private Invoice getInvoiceByIdInternal(Long id) {
        Invoice invoice = invoiceRepository.selectById(id);
        if (invoice == null || invoice.getDeletedAt() != null) {
            throw new InvoiceException("发票不存在");
        }
        return invoice;
    }
}
