package service

import (
	"bufio"
	"encoding/csv"
	"errors"
	"github.com/beancount-gs/script"
	"github.com/gin-gonic/gin"
	"golang.org/x/text/encoding/simplifiedchinese"
	"io"
	"strconv"
	"strings"
	"time"
)

func ImportAliPayCSV(c *gin.Context) {
	ledgerConfig := script.GetLedgerConfigFromContext(c)

	file, _ := c.FormFile("file")
	f, _ := file.Open()
	reader := csv.NewReader(simplifiedchinese.GBK.NewDecoder().Reader(bufio.NewReader(f)))

	result := make([]Transaction, 0)

	currency := "CNY"
	currencySymbol := script.GetCommoditySymbol(ledgerConfig.Id, currency)

	for {
		lines, err := reader.Read()
		if errors.Is(err, io.EOF) {
			break
		} else if err != nil {
			script.LogError(ledgerConfig.Mail, err.Error())
		}
		if len(lines) == 17 {
			transaction, err := importBrowserAliPayCSV(lines, currency, currencySymbol)
			if err != nil {
				script.LogInfo(ledgerConfig.Mail, err.Error())
				continue
			}
			if transaction.Account == "" {
				script.LogInfo(ledgerConfig.Mail, "Invalid transaction")
				continue
			}
			result = append(result, transaction)
		} else if len(lines) == 12 || len(lines) == 13 {
			transaction, err := importMobileAliPayCSV(lines, currency, currencySymbol)
			if err != nil {
				script.LogInfo(ledgerConfig.Mail, err.Error())
				continue
			}
			if transaction.Account == "" {
				script.LogInfo(ledgerConfig.Mail, "Invalid transaction")
				continue
			}
			result = append(result, transaction)
		}
	}

	OK(c, result)
}

func importBrowserAliPayCSV(lines []string, currency string, currencySymbol string) (Transaction, error) {
	dateColumn := strings.Fields(lines[2])
	status := strings.Trim(lines[15], " ")
	account := ""
	if status == "" {
		account = ""
	} else if status == "已收入" {
		account = "Income:"
	} else {
		account = "Expenses:"
	}

	if len(dateColumn) >= 2 {
		return Transaction{
			Id:             strings.Trim(lines[0], " "),
			Date:           strings.Trim(dateColumn[0], " "),
			Payee:          strings.Trim(lines[7], " "),
			Narration:      strings.Trim(lines[8], " "),
			Number:         strings.Trim(lines[9], " "),
			Account:        account,
			Currency:       currency,
			CurrencySymbol: currencySymbol,
		}, nil
	}
	return Transaction{}, errors.New("parse error")
}

func importMobileAliPayCSV(lines []string, currency string, currencySymbol string) (Transaction, error) {
	dateColumn := strings.Fields(lines[0])
	status := strings.Trim(lines[5], " ")
	account := ""
	if status == "" {
		account = ""
	} else if status == "支出" {
		account = "Expenses:"
	} else {
		account = "Income:"
	}

	if len(dateColumn) >= 2 {
		return Transaction{
			Id:             strings.Trim(lines[9], " "),
			Date:           strings.Trim(dateColumn[0], " "),
			Payee:          strings.Trim(lines[2], " "),
			Narration:      strings.Trim(lines[4], " "),
			Number:         strings.Trim(lines[6], " "),
			Account:        account,
			Currency:       currency,
			CurrencySymbol: currencySymbol,
		}, nil
	}
	return Transaction{}, errors.New("parse error")
}

func ImportWxPayCSV(c *gin.Context) {
	ledgerConfig := script.GetLedgerConfigFromContext(c)

	file, _ := c.FormFile("file")
	f, _ := file.Open()
	reader := csv.NewReader(bufio.NewReader(f))

	result := make([]Transaction, 0)

	currency := "CNY"
	currencySymbol := script.GetCommoditySymbol(ledgerConfig.Id, currency)

	for {
		lines, err := reader.Read()
		if err == io.EOF {
			break
		} else if err != nil {
			script.LogError(ledgerConfig.Mail, err.Error())
		}
		if len(lines) > 8 {
			fields := strings.Fields(lines[0])
			status := strings.Trim(lines[4], " ")
			account := ""
			if status == "收入" {
				account = "Income:"
			} else if status == "支出" {
				account = "Expenses:"
			} else {
				continue
			}

			if len(fields) >= 2 {
				result = append(result, Transaction{
					Id:             strings.Trim(lines[8], " "),
					Date:           strings.Trim(fields[0], " "),
					Payee:          strings.Trim(lines[2], " "),
					Narration:      strings.Trim(lines[3], " "),
					Number:         strings.Trim(lines[5], "¥"),
					Account:        account,
					Currency:       currency,
					CurrencySymbol: currencySymbol,
				})
			}
		}
	}

	OK(c, result)
}

func ImportICBCCSV(c *gin.Context) {
	ledgerConfig := script.GetLedgerConfigFromContext(c)

	file, _ := c.FormFile("file")
	f, _ := file.Open()
	reader := csv.NewReader(bufio.NewReader(f))

	result := make([]Transaction, 0)

	currency := "CNY"
	currencySymbol := script.GetCommoditySymbol(ledgerConfig.Id, currency)

	id := 0
	for {
		lines, err := reader.Read()
		if errors.Is(err, io.EOF) {
			break
		} else if err != nil {
			script.LogError(ledgerConfig.Mail, err.Error())
		}
		if len(lines) >= 13 && lines[0] != "交易日期" {
			incomeAmount := formatStr(lines[8])
			expensesAmount := formatStr(lines[9])
			account := ""
			number := ""
			switch {
			case incomeAmount != "":
				account = "Income:"
				number = strings.ReplaceAll(incomeAmount, ",", "")
			case expensesAmount != "":
				account = "Expenses:"
				number = strings.ReplaceAll(expensesAmount, ",", "")
			default:
				continue
			}

			id++
			result = append(result, Transaction{
				Id:             strconv.Itoa(id),
				Date:           formatStr(lines[0]),
				Payee:          formatStr(lines[12]),
				Narration:      formatStr(lines[1]),
				Number:         number,
				Account:        account,
				Currency:       currency,
				CurrencySymbol: currencySymbol,
			})
		}
	}

	OK(c, result)
}

func ImportABCCSV(c *gin.Context) {
	ledgerConfig := script.GetLedgerConfigFromContext(c)

	file, _ := c.FormFile("file")
	f, _ := file.Open()
	reader := csv.NewReader(bufio.NewReader(f))

	result := make([]Transaction, 0)

	currency := "CNY"
	currencySymbol := script.GetCommoditySymbol(ledgerConfig.Id, currency)

	id := 0
	for {
		lines, err := reader.Read()
		if errors.Is(err, io.EOF) {
			break
		} else if err != nil {
			script.LogError(ledgerConfig.Mail, err.Error())
		}
		if len(lines) >= 11 && lines[0] != "交易日期" {
			amount := formatStr(lines[2])
			account := ""
			number := ""
			switch {
			case strings.HasPrefix(amount, "+"):
				account = "Income:"
				number = strings.ReplaceAll(amount, "+", "")
			case strings.HasPrefix(amount, "-"):
				account = "Expenses:"
				number = strings.ReplaceAll(amount, "-", "")
			default:
				continue
			}

			id++
			date, err := time.Parse("20060102", formatStr(lines[0]))
			if err != nil {
				continue
			}
			result = append(result, Transaction{
				Id:             strconv.Itoa(id),
				Date:           date.Format("2006-01-02"),
				Payee:          formatStr(lines[10]),
				Narration:      formatStr(lines[9]),
				Number:         number,
				Account:        account,
				Currency:       currency,
				CurrencySymbol: currencySymbol,
			})
		}
	}

	OK(c, result)
}

func formatStr(str string) string {
	str = strings.Trim(str, "\t")
	return strings.Trim(str, " ")
}
