// Package feishu provides a client for interacting with the Feishu (Lark) API.
// This file contains the notification service for sending various types of
// notifications through Feishu, including permission-related notifications
// and daily statistics reports.
package feishu

import (
	"context"
	"fmt"
	"strings"
	"time"

	"AutoSSO/internal/config"
)

// NotificationService handles sending notifications through Feishu.
// It provides methods for sending permission-related notifications to users
// and daily statistics reports to groups.
//
// Requirements: 10.2, 10.5
type NotificationService struct {
	client *Client
	config *config.FeishuConfig
}

// DailyStats represents the daily statistics for permission operations.
// It contains counts of added and removed permissions grouped by cloud type
// and permission set name.
type DailyStats struct {
	// ReportTime is the time when the report is generated
	ReportTime time.Time

	// AWS statistics
	AWS CloudStats

	// GCP statistics
	GCP CloudStats

	// Azure statistics
	Azure CloudStats

	// Alibaba statistics
	Alibaba CloudStats
}

// CloudStats represents statistics for a single cloud platform.
type CloudStats struct {
	// TotalAdded is the total number of permissions added
	TotalAdded int

	// TotalRemoved is the total number of permissions removed
	TotalRemoved int

	// AddedByPermission maps permission set names to their add counts
	AddedByPermission map[string]int

	// RemovedByPermission maps permission set names to their remove counts
	RemovedByPermission map[string]int

	// NonGeneralRemoved is the count of non-general permission set removals (AWS specific)
	NonGeneralRemoved int
}

// NewNotificationService creates a new notification service.
//
// Parameters:
//   - client: The Feishu client for sending messages
//   - cfg: The Feishu configuration containing chat ID and other settings
//
// Returns a new NotificationService instance.
func NewNotificationService(client *Client, cfg *config.FeishuConfig) *NotificationService {
	return &NotificationService{
		client: client,
		config: cfg,
	}
}

// NotifyPermissionAdded sends a notification when permission is added.
// The notification is sent to the user who requested the permission.
//
// Parameters:
//   - ctx: Context for cancellation
//   - data: The approval data containing user email and permission details
//
// Returns an error if the notification fails to send.
//
// Requirements: 10.2
func (s *NotificationService) NotifyPermissionAdded(ctx context.Context, data *ApprovalData) error {
	if data == nil || data.Email == "" {
		return fmt.Errorf("invalid approval data: missing email")
	}

	title := s.getAddedNotificationTitle(data.CloudType)
	message := s.formatPermissionAddedMessage(data)

	return s.client.SendUserNotification(ctx, data.Email, title, message)
}

// NotifyPermissionExpiring sends a notification when permission is about to expire.
// The notification warns the user that their permission will be revoked soon.
//
// Parameters:
//   - ctx: Context for cancellation
//   - data: The approval data containing user email and permission details
//   - daysRemaining: Number of days until the permission is revoked
//
// Returns an error if the notification fails to send.
//
// Requirements: 10.2
func (s *NotificationService) NotifyPermissionExpiring(ctx context.Context, data *ApprovalData, daysRemaining int) error {
	if data == nil || data.Email == "" {
		return fmt.Errorf("invalid approval data: missing email")
	}

	title := s.getExpiringNotificationTitle(data.CloudType)
	message := s.formatPermissionExpiringMessage(data, daysRemaining)

	return s.client.SendUserNotification(ctx, data.Email, title, message)
}

// NotifyPermissionRemoved sends a notification when permission is removed.
// The notification informs the user that their permission has been revoked.
//
// Parameters:
//   - ctx: Context for cancellation
//   - data: The approval data containing user email and permission details
//
// Returns an error if the notification fails to send.
//
// Requirements: 10.2
func (s *NotificationService) NotifyPermissionRemoved(ctx context.Context, data *ApprovalData) error {
	if data == nil || data.Email == "" {
		return fmt.Errorf("invalid approval data: missing email")
	}

	title := s.getRemovedNotificationTitle(data.CloudType)
	message := s.formatPermissionRemovedMessage(data)

	return s.client.SendUserNotification(ctx, data.Email, title, message)
}

// SendDailyReport sends the daily statistics report to the configured group.
// The report includes permission add and remove statistics for all cloud platforms.
//
// Parameters:
//   - ctx: Context for cancellation
//   - stats: The daily statistics to report
//
// Returns an error if the notification fails to send.
//
// Requirements: 10.5
func (s *NotificationService) SendDailyReport(ctx context.Context, stats *DailyStats) error {
	if stats == nil {
		return fmt.Errorf("invalid stats: nil")
	}

	chatID := s.config.ChatID
	if chatID == "" {
		return fmt.Errorf("chat ID not configured")
	}

	// Send reports for each cloud platform
	var errs []error

	// AWS Report
	if stats.AWS.TotalAdded > 0 || stats.AWS.TotalRemoved > 0 {
		awsTitle := "AWS IAM SSO Service Notice"
		awsMessage := s.formatAWSReport(stats)
		if err := s.client.SendGroupNotification(ctx, chatID, awsTitle, awsMessage); err != nil {
			errs = append(errs, fmt.Errorf("failed to send AWS report: %w", err))
		}
	}

	// GCP Report
	if stats.GCP.TotalAdded > 0 || stats.GCP.TotalRemoved > 0 {
		gcpTitle := "GCP IAM SSO Service Notice"
		gcpMessage := s.formatGCPReport(stats)
		if err := s.client.SendGroupNotification(ctx, chatID, gcpTitle, gcpMessage); err != nil {
			errs = append(errs, fmt.Errorf("failed to send GCP report: %w", err))
		}
	}

	// Azure Report
	if stats.Azure.TotalAdded > 0 || stats.Azure.TotalRemoved > 0 {
		azureTitle := "Azure IAM SSO Service Notice"
		azureMessage := s.formatAzureReport(stats)
		if err := s.client.SendGroupNotification(ctx, chatID, azureTitle, azureMessage); err != nil {
			errs = append(errs, fmt.Errorf("failed to send Azure report: %w", err))
		}
	}

	// Alibaba Report
	if stats.Alibaba.TotalAdded > 0 || stats.Alibaba.TotalRemoved > 0 {
		alibabaTitle := "Alibaba IAM SSO Service Notice"
		alibabaMessage := s.formatAlibabaReport(stats)
		if err := s.client.SendGroupNotification(ctx, chatID, alibabaTitle, alibabaMessage); err != nil {
			errs = append(errs, fmt.Errorf("failed to send Alibaba report: %w", err))
		}
	}

	if len(errs) > 0 {
		return fmt.Errorf("failed to send some reports: %v", errs)
	}

	return nil
}

// getAddedNotificationTitle returns the notification title for permission added.
func (s *NotificationService) getAddedNotificationTitle(cloudType string) string {
	switch cloudType {
	case "AWS":
		return "AWS SSO 权限添加通知"
	case "GCP":
		return "GCP SSO 权限添加通知"
	case "Azure":
		return "Azure SSO 权限添加通知"
	case "Alibaba":
		return "Alibaba SSO 权限添加通知"
	default:
		return "SSO 权限添加通知"
	}
}

// getExpiringNotificationTitle returns the notification title for permission expiring.
func (s *NotificationService) getExpiringNotificationTitle(cloudType string) string {
	switch cloudType {
	case "AWS":
		return "AWS SSO 权限过期提醒"
	case "GCP":
		return "GCP SSO 权限过期提醒"
	case "Azure":
		return "Azure SSO 权限过期提醒"
	case "Alibaba":
		return "Alibaba SSO 权限过期提醒"
	default:
		return "SSO 权限过期提醒"
	}
}

// getRemovedNotificationTitle returns the notification title for permission removed.
func (s *NotificationService) getRemovedNotificationTitle(cloudType string) string {
	switch cloudType {
	case "AWS":
		return "AWS SSO 权限回收通知"
	case "GCP":
		return "GCP SSO 权限回收通知"
	case "Azure":
		return "Azure SSO 权限回收通知"
	case "Alibaba":
		return "Alibaba SSO 权限回收通知"
	default:
		return "SSO 权限回收通知"
	}
}

// formatPermissionAddedMessage formats the message for permission added notification.
func (s *NotificationService) formatPermissionAddedMessage(data *ApprovalData) string {
	permissionList := strings.Join(data.PermissionSets, ", ")

	return fmt.Sprintf(`你好！
你申请的 %s SSO Permission %s 已经授予完成，请检查。
若有任何疑问，请联系安全团队`, data.CloudType, permissionList)
}

// formatPermissionExpiringMessage formats the message for permission expiring notification.
func (s *NotificationService) formatPermissionExpiringMessage(data *ApprovalData, daysRemaining int) string {
	permissionList := strings.Join(data.PermissionSets, ", ")

	return fmt.Sprintf(`你好！
你申请的 %s SSO Permission %s 授权已经过期，系统将在 %d 天后自动回收此权限。
如果需要继续使用该权限，请在权限回收后重新申请，若有任何疑问，请联系产品安全团队。`,
		data.CloudType, permissionList, daysRemaining)
}

// formatPermissionRemovedMessage formats the message for permission removed notification.
func (s *NotificationService) formatPermissionRemovedMessage(data *ApprovalData) string {
	permissionList := strings.Join(data.PermissionSets, ", ")

	return fmt.Sprintf(`你好！
你申请的 %s SSO Permission %s 因授权过期已经被系统自动回收
如果需要继续使用相关权限，请走飞书流程重新申请
若有任何疑问，请联系安全团队`, data.CloudType, permissionList)
}

// formatAWSReport formats the AWS daily statistics report.
func (s *NotificationService) formatAWSReport(stats *DailyStats) string {
	reportTime := stats.ReportTime.Format("2006-01-02 15:04")
	aws := stats.AWS

	var sb strings.Builder
	sb.WriteString(fmt.Sprintf("\n截至 %s ，AWS IAM SSO 授权服务添加和回收权限数据汇总\n\n", reportTime))

	// Added permissions section
	sb.WriteString("一、自动授予 IAM SSO 权限数据\n")
	sb.WriteString(fmt.Sprintf("添加授予权限总数:%d\n", aws.TotalAdded))
	s.writePermissionStats(&sb, aws.AddedByPermission, awsPermissionSets)

	// Removed permissions section
	sb.WriteString("\n二、自动回收过期 IAM SSO 权限\n")
	sb.WriteString(fmt.Sprintf("回收过期权限总数:%d\n", aws.TotalRemoved))
	sb.WriteString("1、通用全集回收\n")
	s.writePermissionStats(&sb, aws.RemovedByPermission, awsPermissionSets)
	sb.WriteString(fmt.Sprintf("2、非通用权限集回收数：%d\n", aws.NonGeneralRemoved))

	return sb.String()
}

// formatGCPReport formats the GCP daily statistics report.
func (s *NotificationService) formatGCPReport(stats *DailyStats) string {
	reportTime := stats.ReportTime.Format("2006-01-02 15:04")
	gcp := stats.GCP

	var sb strings.Builder
	sb.WriteString(fmt.Sprintf("\n截至 %s ，GCP IAM SSO 授权服务添加和回收权限数据汇总\n\n", reportTime))

	// Added permissions section
	sb.WriteString("一、自动授予 IAM SSO 权限数据\n")
	sb.WriteString(fmt.Sprintf("添加授予权限总数:%d\n", gcp.TotalAdded))
	s.writePermissionStats(&sb, gcp.AddedByPermission, gcpPermissionSets)

	// Removed permissions section
	sb.WriteString("\n二、自动回收过期 IAM SSO 权限\n")
	sb.WriteString(fmt.Sprintf("回收过期权限总数:%d\n", gcp.TotalRemoved))
	s.writePermissionStats(&sb, gcp.RemovedByPermission, gcpPermissionSets)

	return sb.String()
}

// formatAzureReport formats the Azure daily statistics report.
func (s *NotificationService) formatAzureReport(stats *DailyStats) string {
	reportTime := stats.ReportTime.Format("2006-01-02 15:04")
	azure := stats.Azure

	var sb strings.Builder
	sb.WriteString(fmt.Sprintf("\n截至 %s ，Azure IAM SSO 授权服务添加和回收权限数据汇总\n\n", reportTime))

	// Added permissions section
	sb.WriteString("一、自动授予 Azure SSO 权限数据\n")
	sb.WriteString(fmt.Sprintf("添加授予权限总数:%d\n", azure.TotalAdded))
	s.writePermissionStats(&sb, azure.AddedByPermission, azurePermissionSets)

	// Removed permissions section
	sb.WriteString("\n二、自动回收过期 IAM SSO 权限\n")
	sb.WriteString(fmt.Sprintf("回收过期权限总数:%d\n", azure.TotalRemoved))
	s.writePermissionStats(&sb, azure.RemovedByPermission, azurePermissionSets)

	return sb.String()
}

// formatAlibabaReport formats the Alibaba daily statistics report.
func (s *NotificationService) formatAlibabaReport(stats *DailyStats) string {
	reportTime := stats.ReportTime.Format("2006-01-02 15:04")
	alibaba := stats.Alibaba

	var sb strings.Builder
	sb.WriteString(fmt.Sprintf("\n截至 %s ，Alibaba IAM SSO 授权服务添加和回收权限数据汇总\n\n", reportTime))

	// Added permissions section
	sb.WriteString("一、自动授予 Alibaba SSO 权限数据\n")
	sb.WriteString(fmt.Sprintf("添加授予权限总数:%d\n", alibaba.TotalAdded))
	s.writePermissionStats(&sb, alibaba.AddedByPermission, alibabaPermissionSets)

	// Removed permissions section
	sb.WriteString("\n二、自动回收过期 IAM SSO 权限\n")
	sb.WriteString(fmt.Sprintf("回收过期权限总数:%d\n", alibaba.TotalRemoved))
	s.writePermissionStats(&sb, alibaba.RemovedByPermission, alibabaPermissionSets)

	return sb.String()
}

// writePermissionStats writes permission statistics to the string builder.
func (s *NotificationService) writePermissionStats(sb *strings.Builder, stats map[string]int, permissionSets []string) {
	for _, perm := range permissionSets {
		count := 0
		if stats != nil {
			count = stats[perm]
		}
		sb.WriteString(fmt.Sprintf("• %s:%d\n", perm, count))
	}
}

// Permission set lists for each cloud platform (used for report formatting)
var awsPermissionSets = []string{
	"DBaaS-Prod-ViewOnly-Role",
	"DBaaS-Prod-OnCall-Role",
	"DBaaS-Prod-Billing-Role",
	"DBaaS-Prod-Admin-Role",
	"PingCAP-SecurityAdmin-Role",
	"DBaaS-Prod-EC2-Role",
	"DBaaS-DevUser-Role",
	"DBaaS-Prod-Web-Role",
	"DBaaS-Prod-OrgOperator-Role",
	"Prod-Tiflow-Engine-RDS",
	"DBaaS-DevLeader-Role",
	"DBaaS-Infra-DevUser-Role",
	"DbaaS-Prod-GlueFullAccess",
	"DBaaS-Prod-OnCall-BastionEC2-Role",
	"DBaaS-Prod-Support-Role",
}

var gcpPermissionSets = []string{
	"DBaaS-Prod-ViewOnly-Role",
	"DBaaS-Prod-DevUser-Role",
	"DBaaS-Prod-DevSpecial-Role",
	"DBaaS-Prod-DevAdmin-Role",
	"DBaaS-Prod-Bigquery-Role",
	"DBaaS-Prod-Billing-Admin-Role",
	"DBaaS-Prod-Billing-ViewOnly-Role",
	"DBaaS-Prod-Admin-Role",
	"DBaaS-Prod-Security-Role",
	"DBaaS-Prod-Oncall-Role",
}

var azurePermissionSets = []string{
	"DBaaS-Prod-ViewOnly-Role",
	"DBaaS-Prod-DevUser-Role",
	"DBaaS-Prod-DevSpecial-Role",
	"DBaaS-Prod-DevAdmin-Role",
	"DBaaS-Prod-SQL-Role",
	"DBaaS-Prod-Billing-Role",
	"DBaaS-Prod-Admin-Role",
	"DBaaS-Prod-Security-Role",
}

var alibabaPermissionSets = []string{
	"DBaaS-Prod-ViewOnly-Role",
	"DBaaS-Prod-DevUser-Role",
	"DBaaS-Prod-DevSpecial-Role",
	"DBaaS-Prod-DevAdmin-Role",
	"DBaaS-Prod-SQL-Role",
	"DBaaS-Prod-Billing-Role",
	"DBaaS-Prod-Admin-Role",
	"DBaaS-Prod-Security-Role",
}

// NewDailyStats creates a new DailyStats instance with initialized maps.
func NewDailyStats() *DailyStats {
	return &DailyStats{
		ReportTime: time.Now(),
		AWS: CloudStats{
			AddedByPermission:   make(map[string]int),
			RemovedByPermission: make(map[string]int),
		},
		GCP: CloudStats{
			AddedByPermission:   make(map[string]int),
			RemovedByPermission: make(map[string]int),
		},
		Azure: CloudStats{
			AddedByPermission:   make(map[string]int),
			RemovedByPermission: make(map[string]int),
		},
		Alibaba: CloudStats{
			AddedByPermission:   make(map[string]int),
			RemovedByPermission: make(map[string]int),
		},
	}
}

// RecordPermissionAdded records a permission addition in the statistics.
func (s *DailyStats) RecordPermissionAdded(cloudType string, permissionSet string) {
	switch cloudType {
	case "AWS":
		s.AWS.TotalAdded++
		s.AWS.AddedByPermission[permissionSet]++
	case "GCP":
		s.GCP.TotalAdded++
		s.GCP.AddedByPermission[permissionSet]++
	case "Azure":
		s.Azure.TotalAdded++
		s.Azure.AddedByPermission[permissionSet]++
	case "Alibaba":
		s.Alibaba.TotalAdded++
		s.Alibaba.AddedByPermission[permissionSet]++
	}
}

// RecordPermissionRemoved records a permission removal in the statistics.
func (s *DailyStats) RecordPermissionRemoved(cloudType string, permissionSet string, isNonGeneral bool) {
	switch cloudType {
	case "AWS":
		s.AWS.TotalRemoved++
		if isNonGeneral {
			s.AWS.NonGeneralRemoved++
		} else {
			s.AWS.RemovedByPermission[permissionSet]++
		}
	case "GCP":
		s.GCP.TotalRemoved++
		s.GCP.RemovedByPermission[permissionSet]++
	case "Azure":
		s.Azure.TotalRemoved++
		s.Azure.RemovedByPermission[permissionSet]++
	case "Alibaba":
		s.Alibaba.TotalRemoved++
		s.Alibaba.RemovedByPermission[permissionSet]++
	}
}
