package service

import (
	"bdrp-server/app/main/api/internal/config"
	"bdrp-server/app/main/model"
	"bytes"
	"context"
	"database/sql"
	"fmt"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/jung-kurt/gofpdf"
	"github.com/pkg/errors"
	"github.com/zeromicro/go-zero/core/logx"
)

type AuthorizationService struct {
	config          config.Config
	authDocModel    model.AuthorizationDocumentModel
	fileStoragePath string
	fileBaseURL     string
}

// NewAuthorizationService 创建授权书服务实例
func NewAuthorizationService(c config.Config, authDocModel model.AuthorizationDocumentModel) *AuthorizationService {
	absStoragePath := determineStoragePath()

	return &AuthorizationService{
		config:          c,
		authDocModel:    authDocModel,
		fileStoragePath: absStoragePath,
		fileBaseURL:     c.Authorization.FileBaseURL, // 从配置文件读取
	}
}

// GenerateAuthorizationDocument 生成授权书PDF
func (s *AuthorizationService) GenerateAuthorizationDocument(
	ctx context.Context,
	userID int64,
	orderID int64,
	queryID int64,
	userInfo map[string]interface{},
) (*model.AuthorizationDocument, error) {
	// 1. 生成PDF内容
	pdfBytes, err := s.generatePDFContent(userInfo)
	if err != nil {
		return nil, errors.Wrapf(err, "生成PDF内容失败")
	}

	// 2. 创建文件存储目录
	year := time.Now().Format("2006")
	month := time.Now().Format("01")
	dirPath := filepath.Join(s.fileStoragePath, year, month)
	if err := os.MkdirAll(dirPath, 0755); err != nil {
		return nil, errors.Wrapf(err, "创建存储目录失败: %s", dirPath)
	}

	// 3. 生成文件名和路径
	fileName := fmt.Sprintf("auth_%d_%d_%s.pdf", userID, orderID, time.Now().Format("20060102_150405"))
	filePath := filepath.Join(dirPath, fileName)
	// 只存储相对路径，不包含域名
	relativePath := fmt.Sprintf("%s/%s/%s", year, month, fileName)

	// 4. 保存PDF文件
	if err := os.WriteFile(filePath, pdfBytes, 0644); err != nil {
		return nil, errors.Wrapf(err, "保存PDF文件失败: %s", filePath)
	}

	// 5. 保存到数据库
	authDoc := &model.AuthorizationDocument{
		UserId:     userID,
		OrderId:    orderID,
		QueryId:    queryID,
		FileName:   fileName,
		FilePath:   filePath,
		FileUrl:    relativePath, // 只存储相对路径
		FileSize:   int64(len(pdfBytes)),
		FileType:   "pdf",
		Status:     "active",
		ExpireTime: sql.NullTime{Valid: false}, // 永久保留，不设置过期时间
	}

	result, err := s.authDocModel.Insert(ctx, nil, authDoc)
	if err != nil {
		// 如果数据库保存失败，删除已创建的文件
		os.Remove(filePath)
		return nil, errors.Wrapf(err, "保存授权书记录失败")
	}

	authDoc.Id, _ = result.LastInsertId()
	logx.Infof("授权书生成成功: userID=%d, orderID=%d, filePath=%s", userID, orderID, filePath)

	return authDoc, nil
}

// GetFullFileURL 获取完整的文件访问URL
func (s *AuthorizationService) GetFullFileURL(relativePath string) string {
	if relativePath == "" {
		return ""
	}
	return fmt.Sprintf("%s/%s", s.fileBaseURL, relativePath)
}

// ResolveFilePath 根据存储的路径信息解析出本地文件的绝对路径
func (s *AuthorizationService) ResolveFilePath(filePath string, relativePath string) string {
	candidates := []string{}

	cleanRelative := func(p string) string {
		p = strings.TrimPrefix(p, "/")
		p = strings.TrimPrefix(p, "\\")
		normalized := filepath.ToSlash(p)
		if strings.HasPrefix(normalized, "http://") || strings.HasPrefix(normalized, "https://") {
			if parsed, err := url.Parse(normalized); err == nil {
				normalized = filepath.ToSlash(strings.TrimPrefix(parsed.Path, "/"))
			}
		}
		normalized = strings.TrimPrefix(normalized, "data/authorization_docs/")
		normalized = strings.TrimPrefix(normalized, "authorization_docs/")
		normalized = strings.TrimPrefix(normalized, "./")
		normalized = strings.TrimPrefix(normalized, "../")
		return normalized
	}

	if filePath != "" {
		candidates = append(candidates, filePath)
	}
	if relativePath != "" {
		candidates = append(candidates, filepath.Join(s.fileStoragePath, filepath.FromSlash(cleanRelative(relativePath))))
	}
	if filePath != "" {
		cleaned := filepath.Clean(filePath)
		if strings.HasPrefix(cleaned, s.fileStoragePath) {
			candidates = append(candidates, cleaned)
		} else {
			trimmed := strings.TrimPrefix(cleaned, "data"+string(os.PathSeparator)+"authorization_docs"+string(os.PathSeparator))
			trimmed = strings.TrimPrefix(trimmed, "data/authorization_docs/")
			if trimmed != cleaned {
				candidates = append(candidates, filepath.Join(s.fileStoragePath, filepath.FromSlash(cleanRelative(trimmed))))
			}
			if !filepath.IsAbs(cleaned) {
				candidates = append(candidates, filepath.Join(s.fileStoragePath, filepath.FromSlash(cleanRelative(cleaned))))
			}
		}
	}

	for _, candidate := range candidates {
		if candidate == "" {
			continue
		}
		pathCandidate := candidate
		if !filepath.IsAbs(pathCandidate) {
			if absPath, err := filepath.Abs(pathCandidate); err == nil {
				pathCandidate = absPath
			}
		}
		if statErr := checkFileExists(pathCandidate); statErr == nil {
			return pathCandidate
		}
	}

	logx.Errorf("授权书文件路径解析失败 filePath=%s fileUrl=%s candidates=%v", filePath, relativePath, candidates)

	return ""
}

func determineStoragePath() string {
	candidatePaths := []string{
		"data/authorization_docs",
		"../data/authorization_docs",
		"../../data/authorization_docs",
		"../../../data/authorization_docs",
	}

	for _, candidate := range candidatePaths {
		absPath, err := filepath.Abs(candidate)
		if err != nil {
			logx.Errorf("解析授权书存储路径失败: %s, err=%v", candidate, err)
			continue
		}
		if info, err := os.Stat(absPath); err == nil && info.IsDir() {
			logx.Infof("授权书存储路径选择: %s", absPath)
			return absPath
		}
	}

	// 如果没有现成的目录，使用第一个候选的绝对路径
	absPath, err := filepath.Abs(candidatePaths[0])
	if err != nil {
		logx.Errorf("解析默认授权书存储路径失败，使用相对路径: %s, err=%v", candidatePaths[0], err)
		return candidatePaths[0]
	}
	logx.Infof("授权书存储路径创建: %s", absPath)
	return absPath
}

func checkFileExists(path string) error {
	info, err := os.Stat(path)
	if err != nil {
		return err
	}
	if info.IsDir() {
		return fmt.Errorf("path %s is directory", path)
	}
	return nil
}

// generatePDFContent 生成PDF内容
func (s *AuthorizationService) generatePDFContent(userInfo map[string]interface{}) ([]byte, error) {
	// 创建PDF文档
	pdf := gofpdf.New("P", "mm", "A4", "")
	pdf.AddPage()

	// 添加中文字体支持 - 参考imageService的路径处理方式
	fontPaths := []string{
		"static/SIMHEI.TTF",              // 相对于工作目录的路径（与imageService一致）
		"/app/static/SIMHEI.TTF",         // Docker容器内的字体文件
		"app/main/api/static/SIMHEI.TTF", // 开发环境备用路径
	}

	// 尝试添加字体
	fontAdded := false
	for _, fontPath := range fontPaths {
		if _, err := os.Stat(fontPath); err == nil {
			pdf.AddUTF8Font("ChineseFont", "", fontPath)
			fontAdded = true
			logx.Infof("成功加载字体: %s", fontPath)
			break
		} else {
			logx.Debugf("字体文件不存在: %s, 错误: %v", fontPath, err)
		}
	}

	// 如果没有找到字体文件，使用默认字体，并记录警告
	if !fontAdded {
		pdf.SetFont("Arial", "", 12)
		logx.Errorf("未找到中文字体文件，使用默认Arial字体，可能无法正确显示中文")
	} else {
		// 设置默认字体
		pdf.SetFont("ChineseFont", "", 12)
	}

	// 获取用户信息
	name := getUserInfoString(userInfo, "name")
	idCard := getUserInfoString(userInfo, "id_card")

	// 生成当前日期
	currentDate := time.Now().Format("2006年1月2日")

	// 设置标题样式 - 大字体、居中
	if fontAdded {
		pdf.SetFont("ChineseFont", "", 20) // 使用20号字体
	} else {
		pdf.SetFont("Arial", "", 20)
	}
	pdf.CellFormat(0, 15, "授权书", "", 1, "C", false, 0, "")

	// 添加空行
	pdf.Ln(5)

	// 设置正文样式 - 正常字体
	if fontAdded {
		pdf.SetFont("ChineseFont", "", 12)
	} else {
		pdf.SetFont("Arial", "", 12)
	}

	// 构建授权书内容（与前端 Authorization.vue 保持一致）
	content := fmt.Sprintf(`戎行技术有限公司：
本人（姓名：%s／身份证号码：%s）拟向贵司申请业务，贵司需要了解本人相关状况，用于查询大数据分析报告，因此本人特同意并不可撤销的授权：

（一）贵司向依法成立的第三方服务商（包括但不限于天津津北数字产业发展集团有限公司）根据本人提交的信息进行核实；并有权通过前述第三方服务机构查询、使用本人的身份信息、电话号码等，查询本人信息（包括但不限于学历、婚姻、资产状况及对信息主体产生负面影响的不良信息），出具相关报告。
（二）第三方服务商应当在上述处理目的、处理方式和个人信息的种类等范围内处理个人信息。变更原先的处理目的、处理方式的，应当依法重新取得您的同意。

本人在此声明已充分理解上述授权条款含义，知晓并自愿承担上述因收集等本人数据可能会给本人的生活行为（评分）结果产生不利影响，以及该等数据被使用者依法提供给第三方后被他人不当利用的风险，但本人仍同意上述授权。

特别提示：
为了保障您的合法权益，请您务必阅读并充分理解与遵守本授权书；若您不接受本授权书的任何条款，请您立即终止授权。贵司已经对上述事宜及其风险向本人做了充分说明，本人已知晓并同意。
你通过“赤眉”APP或代理商推广查询模式，自愿支付相应费用，用于购买戎行技术有限公司的大数据报告产品。
你向戎行技术有限公司的支付方式为：戎行技术有限公司及其关联公司的支付宝及微信账户。
本授权书一经本人在网上点击勾选同意即完成签署。本授权书是本人真实意思表示，本人同意承担由此带来的一切法律后果。

授权人：%s
身份证号：%s
签署时间：%s`, name, idCard, name, idCard, currentDate)

	// 将内容写入PDF
	pdf.MultiCell(0, 6, content, "", "", false)

	// 生成PDF字节数组
	var buf bytes.Buffer
	err := pdf.Output(&buf)
	if err != nil {
		return nil, errors.Wrapf(err, "生成PDF字节数组失败")
	}

	return buf.Bytes(), nil
}

// getUserInfoString 安全获取用户信息字符串
func getUserInfoString(userInfo map[string]interface{}, key string) string {
	if value, exists := userInfo[key]; exists {
		if str, ok := value.(string); ok {
			return str
		}
	}
	return ""
}
