package feishu

import (
	"encoding/json"
	"fmt"
	"strings"

	"github.com/pingcap-inc/clinic/clinic_data_service/pkg/log"
	"go.uber.org/zap"
)

// TableFieldConfig Table field configuration structure
type TableFieldConfig struct {
	FieldName string
	Type      int
	Property  map[string]interface{}
	IsHeader  bool // Indicates whether it is displayed as a table header only
}

// DefaultTableFields Default table field definitions (generated from configuration)
var DefaultTableFields = func() []CreateFieldRequest {
	var fields []CreateFieldRequest
	for _, config := range SlowQueryTableFieldConfigs {
		if !config.IsHeader { // Only add fields that are not header-only
			fields = append(fields, CreateFieldRequest{
				FieldName: config.FieldName,
				Type:      config.Type,
				Property:  config.Property,
			})
		}
	}
	return fields
}()

// SlowQueryTableHeaders Default table headers (generated from configuration)
// var SlowQueryTableHeaders = func() []string {
// 	var headers []string
// 	for _, config := range SlowQueryTableFieldConfigs {
// 		headers = append(headers, config.FieldName)
// 	}
// 	return headers
// }()

// GetTableHeaders get table headers from field configs
func GetTableHeaders(fieldConfigs []TableFieldConfig) []string {
	var headers []string
	for _, config := range fieldConfigs {
		headers = append(headers, config.FieldName)
	}
	return headers
}

func GetCreateFieldRequest(fieldConfigs []TableFieldConfig) []CreateFieldRequest {
	var fields []CreateFieldRequest
	for _, config := range fieldConfigs {
		if !config.IsHeader { // Only add fields that are not header-only
			fields = append(fields, CreateFieldRequest{
				FieldName: config.FieldName,
				Type:      config.Type,
				Property:  config.Property,
			})
		}
	}
	return fields
}

// BiTable related structures

// BiTableBlockRequest request for creating BiTable block
type BiTableBlockRequest struct {
	Children []BiTableBlock `json:"children"`
}

type BiTableBlock struct {
	BlockType int         `json:"block_type"`
	BiTable   BiTableData `json:"bitable,omitempty"`
}

type BiTableData struct {
	Token    string `json:"token,omitempty"`
	ViewType int    `json:"view_type,omitempty"`
}

// CreateBiTableBlockResponse response for creating BiTable block
type CreateBiTableBlockResponse struct {
	Code int    `json:"code"`
	Msg  string `json:"msg"`
	Data struct {
		Children []struct {
			BlockID   string `json:"block_id"`
			BlockType int    `json:"block_type"`
			BiTable   struct {
				Token string `json:"token"`
			} `json:"bitable"`
		} `json:"children"`
	} `json:"data"`
}

// ListFieldsResponse response for listing table fields
type ListFieldsResponse struct {
	Code int    `json:"code"`
	Msg  string `json:"msg"`
	Data struct {
		Items []struct {
			FieldID   string `json:"field_id"`
			FieldName string `json:"field_name"`
			Type      int    `json:"type"`
			IsPrimary bool   `json:"is_primary"`
		} `json:"items"`
	} `json:"data"`
}

// UpdateFieldRequest request for updating field
type UpdateFieldRequest struct {
	FieldName string `json:"field_name"`
	Type      int    `json:"type"`
}

// UpdateFieldResponse response for updating field
type UpdateFieldResponse struct {
	Code int    `json:"code"`
	Msg  string `json:"msg"`
	Data struct {
		Field struct {
			FieldID   string `json:"field_id"`
			FieldName string `json:"field_name"`
			Type      int    `json:"type"`
		} `json:"field"`
	} `json:"data"`
}

// DeleteFieldResponse response for deleting field
type DeleteFieldResponse struct {
	Code int    `json:"code"`
	Msg  string `json:"msg"`
}

// CreateFieldRequest request for creating field
type CreateFieldRequest struct {
	FieldName string                 `json:"field_name"`
	Type      int                    `json:"type"`
	Property  map[string]interface{} `json:"property,omitempty"`
}

// CreateFieldResponse response for creating field
type CreateFieldResponse struct {
	Code int    `json:"code"`
	Msg  string `json:"msg"`
	Data struct {
		Field struct {
			FieldID   string `json:"field_id"`
			FieldName string `json:"field_name"`
			Type      int    `json:"type"`
		} `json:"field"`
	} `json:"data"`
}

// BatchCreateRecordRequest request for batch creating records
type BatchCreateRecordRequest struct {
	Records []RecordData `json:"records"`
}

// RecordData record data structure
type RecordData struct {
	Fields map[string]interface{} `json:"fields"`
}

// BatchCreateRecordResponse response for batch creating records
type BatchCreateRecordResponse struct {
	Code int    `json:"code"`
	Msg  string `json:"msg"`
	Data struct {
		Records []struct {
			RecordID string                 `json:"record_id"`
			Fields   map[string]interface{} `json:"fields"`
		} `json:"records"`
	} `json:"data"`
}

// SearchRecordRequest request for searching records
type SearchRecordRequest struct {
	PageSize int `json:"page_size,omitempty"`
}

// SearchRecordResponse response for searching records
type SearchRecordResponse struct {
	Code int    `json:"code"`
	Msg  string `json:"msg"`
	Data struct {
		Items []struct {
			RecordID string                 `json:"record_id"`
			Fields   map[string]interface{} `json:"fields"`
		} `json:"items"`
		HasMore   bool   `json:"has_more"`
		PageToken string `json:"page_token"`
		Total     int    `json:"total"`
	} `json:"data"`
}

// BatchDeleteRecordRequest request for batch deleting records
type BatchDeleteRecordRequest struct {
	Records []string `json:"records"`
}

// BatchDeleteRecordResponse response for batch deleting records
type BatchDeleteRecordResponse struct {
	Code int    `json:"code"`
	Msg  string `json:"msg"`
	Data struct {
		Records []struct {
			Deleted  bool   `json:"deleted"`
			RecordID string `json:"record_id"`
		} `json:"records"`
	} `json:"data"`
}

// CreateBiTableAndInsertData creates a BiTable and inserts data with complete workflow [Add Columns]
func (c *Client) CreateBiTableAndInsertData(documentID, parentBlockID string, data [][]CellValue, tableFieldConfig []TableFieldConfig) (string, error) {
	if len(data) == 0 {
		log.PlainInfo("data is empty, skip create bitable")
		return "", nil
	}
	// 1. Create BiTable block
	appToken, tableID, err := c.CreateBiTableBlock(documentID, parentBlockID)
	if err != nil {
		return "", fmt.Errorf("create bitable block failed: %w", err)
	}

	// 2. Get existing fields list
	fields, err := c.ListTableFields(appToken, tableID)
	if err != nil {
		return appToken, fmt.Errorf("list fields failed: %w", err)
	}

	// 3. Update first field to link type
	if len(fields) > 0 {
		if err := c.UpdateTableField(appToken, tableID, fields[0].FieldID, "Digest（Click to list）", 15); err != nil {
			return appToken, fmt.Errorf("update first field failed: %w", err)
		}

		// 4. Delete all fields after the first one
		for i := 1; i < len(fields); i++ {
			if err := c.DeleteTableField(appToken, tableID, fields[i].FieldID); err != nil {
				// Ignore deletion errors and continue
			}
		}
	}

	// 5. Add new fields [Add Columns]
	// newFields := DefaultTableFields
	newFields := GetCreateFieldRequest(tableFieldConfig)

	for _, field := range newFields {
		if err := c.CreateTableFieldWithProperty(appToken, tableID, field); err != nil {
			// Ignore field creation errors and continue
		}
	}

	// 6. Delete initial empty records
	if err := c.DeleteInitialEmptyRecords(appToken, tableID); err != nil {
		// Ignore deletion errors and continue
	}

	// 7. Insert data
	if len(data) > 0 {
		if err := c.BatchCreateRecords(appToken, tableID, data, tableFieldConfig); err != nil {
			return appToken, fmt.Errorf("insert data failed: %w", err)
		}
	}

	return appToken, nil
}

// CreateBiTableBlock creates a BiTable block
func (c *Client) CreateBiTableBlock(documentID, parentBlockID string) (string, string, error) {
	if c.AccessToken == "" {
		if err := c.GetAccessToken(); err != nil {
			return "", "", fmt.Errorf("get access token failed: %w", err)
		}
	}

	url := fmt.Sprintf("https://open.feishu.cn/open-apis/docx/v1/documents/%s/blocks/%s/children", documentID, parentBlockID)

	payload := BiTableBlockRequest{
		Children: []BiTableBlock{
			{
				BlockType: 18, // BiTable block type
				BiTable: BiTableData{
					ViewType: 1,
				},
			},
		},
	}
	log.PlainInfo("feishu create bitable block request:" + url)
	log.PlainInfo("feishu create bitable block request payload", zap.Any("payload", payload))
	respBody, err := c.makeRequest("POST", url, payload)
	log.PlainInfo("feishu create bitable block response", zap.Any("response", respBody))
	if err != nil {
		return "", "", fmt.Errorf("create bitable block failed: %w", err)
	}

	var response CreateBiTableBlockResponse
	if err := json.Unmarshal(respBody, &response); err != nil {
		return "", "", fmt.Errorf("unmarshal response failed: %w", err)
	}

	if response.Code != 0 {
		return "", "", fmt.Errorf("create bitable block failed (code: %d): %s", response.Code, response.Msg)
	}

	if len(response.Data.Children) == 0 {
		return "", "", fmt.Errorf("no bitable block created")
	}

	token := response.Data.Children[0].BiTable.Token

	// Parse token: first part is app_token, second part is table_id
	parts := strings.Split(token, "_")
	if len(parts) < 2 {
		return "", "", fmt.Errorf("invalid token format: %s", token)
	}

	appToken := parts[0]
	tableID := parts[1]

	return appToken, tableID, nil
}

// FieldInfo field information structure
type FieldInfo struct {
	FieldID   string
	FieldName string
	Type      int
	IsPrimary bool
}

// ListTableFields gets table field list
func (c *Client) ListTableFields(appToken, tableID string) ([]FieldInfo, error) {
	if c.AccessToken == "" {
		if err := c.GetAccessToken(); err != nil {
			return nil, fmt.Errorf("get access token failed: %w", err)
		}
	}

	url := fmt.Sprintf("https://open.feishu.cn/open-apis/bitable/v1/apps/%s/tables/%s/fields", appToken, tableID)

	respBody, err := c.makeRequest("GET", url, nil)
	if err != nil {
		return nil, fmt.Errorf("list fields failed: %w", err)
	}

	var response ListFieldsResponse
	if err := json.Unmarshal(respBody, &response); err != nil {
		return nil, fmt.Errorf("unmarshal response failed: %w", err)
	}

	if response.Code != 0 {
		return nil, fmt.Errorf("list fields failed (code: %d): %s", response.Code, response.Msg)
	}

	// Convert to FieldInfo structure
	fields := make([]FieldInfo, len(response.Data.Items))
	for i, item := range response.Data.Items {
		fields[i] = FieldInfo{
			FieldID:   item.FieldID,
			FieldName: item.FieldName,
			Type:      item.Type,
			IsPrimary: item.IsPrimary,
		}
	}

	return fields, nil
}

// UpdateTableField updates table field
func (c *Client) UpdateTableField(appToken, tableID, fieldID, fieldName string, fieldType int) error {
	if c.AccessToken == "" {
		if err := c.GetAccessToken(); err != nil {
			return fmt.Errorf("get access token failed: %w", err)
		}
	}

	url := fmt.Sprintf("https://open.feishu.cn/open-apis/bitable/v1/apps/%s/tables/%s/fields/%s", appToken, tableID, fieldID)

	payload := UpdateFieldRequest{
		FieldName: fieldName,
		Type:      fieldType,
	}

	respBody, err := c.makeRequest("PUT", url, payload)
	if err != nil {
		return fmt.Errorf("update field failed: %w", err)
	}

	var response UpdateFieldResponse
	if err := json.Unmarshal(respBody, &response); err != nil {
		return fmt.Errorf("unmarshal response failed: %w", err)
	}

	if response.Code != 0 {
		return fmt.Errorf("update field failed (code: %d): %s", response.Code, response.Msg)
	}

	return nil
}

// DeleteTableField deletes table field
func (c *Client) DeleteTableField(appToken, tableID, fieldID string) error {
	if c.AccessToken == "" {
		if err := c.GetAccessToken(); err != nil {
			return fmt.Errorf("get access token failed: %w", err)
		}
	}

	url := fmt.Sprintf("https://open.feishu.cn/open-apis/bitable/v1/apps/%s/tables/%s/fields/%s", appToken, tableID, fieldID)

	respBody, err := c.makeRequest("DELETE", url, nil)
	if err != nil {
		return fmt.Errorf("delete field failed: %w", err)
	}

	var response DeleteFieldResponse
	if err := json.Unmarshal(respBody, &response); err != nil {
		return fmt.Errorf("unmarshal response failed: %w", err)
	}

	if response.Code != 0 {
		return fmt.Errorf("delete field failed (code: %d): %s", response.Code, response.Msg)
	}

	return nil
}

// CreateTableField creates table field (simple version)
func (c *Client) CreateTableField(appToken, tableID, fieldName string, fieldType int) error {
	field := CreateFieldRequest{
		FieldName: fieldName,
		Type:      fieldType,
	}
	return c.CreateTableFieldWithProperty(appToken, tableID, field)
}

// CreateTableFieldWithProperty creates table field with property configuration
func (c *Client) CreateTableFieldWithProperty(appToken, tableID string, field CreateFieldRequest) error {
	if c.AccessToken == "" {
		if err := c.GetAccessToken(); err != nil {
			return fmt.Errorf("get access token failed: %w", err)
		}
	}

	url := fmt.Sprintf("https://open.feishu.cn/open-apis/bitable/v1/apps/%s/tables/%s/fields", appToken, tableID)

	respBody, err := c.makeRequest("POST", url, field)
	if err != nil {
		return fmt.Errorf("create field failed: %w", err)
	}

	var response CreateFieldResponse
	if err := json.Unmarshal(respBody, &response); err != nil {
		return fmt.Errorf("unmarshal response failed: %w", err)
	}

	if response.Code != 0 {
		return fmt.Errorf("create field failed (code: %d): %s", response.Code, response.Msg)
	}

	return nil
}

// SearchRecords searches records
func (c *Client) SearchRecords(appToken, tableID string) ([]string, error) {
	if c.AccessToken == "" {
		if err := c.GetAccessToken(); err != nil {
			return nil, fmt.Errorf("get access token failed: %w", err)
		}
	}

	url := fmt.Sprintf("https://open.feishu.cn/open-apis/bitable/v1/apps/%s/tables/%s/records/search", appToken, tableID)

	payload := SearchRecordRequest{
		PageSize: 500, // Set page size
	}

	respBody, err := c.makeRequest("POST", url, payload)
	if err != nil {
		return nil, fmt.Errorf("search records failed: %w", err)
	}

	var response SearchRecordResponse
	if err := json.Unmarshal(respBody, &response); err != nil {
		return nil, fmt.Errorf("unmarshal response failed: %w", err)
	}

	if response.Code != 0 {
		return nil, fmt.Errorf("search records failed (code: %d): %s", response.Code, response.Msg)
	}

	// Collect all record IDs
	recordIDs := make([]string, len(response.Data.Items))
	for i, item := range response.Data.Items {
		recordIDs[i] = item.RecordID
	}

	return recordIDs, nil
}

// BatchDeleteRecords batch deletes records
func (c *Client) BatchDeleteRecords(appToken, tableID string, recordIDs []string) error {
	if c.AccessToken == "" {
		if err := c.GetAccessToken(); err != nil {
			return fmt.Errorf("get access token failed: %w", err)
		}
	}

	if len(recordIDs) == 0 {
		return nil
	}

	url := fmt.Sprintf("https://open.feishu.cn/open-apis/bitable/v1/apps/%s/tables/%s/records/batch_delete", appToken, tableID)

	payload := BatchDeleteRecordRequest{
		Records: recordIDs,
	}

	respBody, err := c.makeRequest("POST", url, payload)
	if err != nil {
		return fmt.Errorf("batch delete records failed: %w", err)
	}

	var response BatchDeleteRecordResponse
	if err := json.Unmarshal(respBody, &response); err != nil {
		return fmt.Errorf("unmarshal response failed: %w", err)
	}

	if response.Code != 0 {
		return fmt.Errorf("batch delete records failed (code: %d): %s", response.Code, response.Msg)
	}

	return nil
}

// DeleteInitialEmptyRecords deletes initial empty records
func (c *Client) DeleteInitialEmptyRecords(appToken, tableID string) error {
	recordIDs, err := c.SearchRecords(appToken, tableID)
	if err != nil {
		return fmt.Errorf("search records failed: %w", err)
	}

	if len(recordIDs) > 0 {
		if err := c.BatchDeleteRecords(appToken, tableID, recordIDs); err != nil {
			return fmt.Errorf("delete records failed: %w", err)
		}
	}

	return nil
}

// BatchCreateRecords batch creates records [Add Columns]
func (c *Client) BatchCreateRecords(appToken, tableID string, data [][]CellValue, fieldConfigs []TableFieldConfig) error {
	if c.AccessToken == "" {
		if err := c.GetAccessToken(); err != nil {
			return fmt.Errorf("get access token failed: %w", err)
		}
	}

	if len(data) == 0 {
		log.PlainError("BatchCreateRecords failed", zap.String("msg", "data is empty"))
		return fmt.Errorf("data is empty")
	}

	// Add debug log
	// fmt.Printf("BatchCreateRecords: appToken=%s, tableID=%s, data rows=%d\n", appToken, tableID, len(data))

	// Predefined field names
	headers := GetTableHeaders(fieldConfigs)

	// Construct record data
	records := make([]RecordData, len(data))
	for i, row := range data {
		fields := make(map[string]interface{})
		for j, cell := range row {
			if j < len(headers) {
				// Handle different types of cell data
				switch v := cell.(type) {
				case LinkCell:
					// Link type needs special handling
					fields[headers[j]] = map[string]interface{}{
						"text": v.Text,
						"link": v.Link,
					}
				default:
					// Other types assign directly
					fields[headers[j]] = v
				}
			}
		}
		records[i] = RecordData{Fields: fields}
	}

	url := fmt.Sprintf("https://open.feishu.cn/open-apis/bitable/v1/apps/%s/tables/%s/records/batch_create", appToken, tableID)

	payload := BatchCreateRecordRequest{
		Records: records,
	}

	// Add request payload log
	// payloadJSON, _ := json.Marshal(payload)

	respBody, err := c.makeRequest("POST", url, payload)
	if err != nil {
		log.PlainError("BatchCreateRecords failed", zap.Error(err))
		return err
	}

	var response BatchCreateRecordResponse
	if err := json.Unmarshal(respBody, &response); err != nil {
		log.PlainError("BatchCreateRecords failed", zap.Error(err))
		return err
	}

	if response.Code != 0 {
		log.PlainError(string(respBody))

		log.PlainError("BatchCreateRecords failed", zap.String("msg", response.Msg))
		return err
	}

	return nil
}
