package com.example.demo.account;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class AccountService {

    private final JdbcTemplate jdbcTemplate;

    public AccountService(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    public Object list(Long shopId, String kw, Integer status, int page, int size) {
        StringBuilder sql = new StringBuilder("SELECT id, name, type, bank_name, bank_account, balance, status FROM accounts WHERE shop_id=?");
        java.util.List<Object> ps = new java.util.ArrayList<>(); ps.add(shopId);
        if (status != null) { sql.append(" AND status=?"); ps.add(status); }
        if (kw != null && !kw.isBlank()) { sql.append(" AND (name LIKE ? OR bank_name LIKE ? OR bank_account LIKE ?)"); ps.add('%'+kw+'%'); ps.add('%'+kw+'%'); ps.add('%'+kw+'%'); }
        sql.append(" ORDER BY id DESC LIMIT ? OFFSET ?"); ps.add(size); ps.add(page * size);
        List<Map<String,Object>> list = jdbcTemplate.queryForList(sql.toString(), ps.toArray());
        Map<String,Object> body = new HashMap<>();
        body.put("list", list);
        return body;
    }

    @Transactional
    public Long create(Long shopId, Long userId, AccountDtos.CreateAccountRequest req) {
        if (req == null || req.name == null || req.name.isBlank()) throw new IllegalArgumentException("账户名称必填");
        String type = (req.type == null || req.type.isBlank()) ? "cash" : req.type.toLowerCase();
        int status = req.status == null ? 1 : req.status;
        jdbcTemplate.update("INSERT INTO accounts (shop_id,user_id,name,type,bank_name,bank_account,balance,status,created_at,updated_at) VALUES (?,?,?,?,?,?,0,?,NOW(),NOW())",
                shopId, userId, req.name, type, req.bankName, req.bankAccount, status);
        Long id = jdbcTemplate.queryForObject("SELECT id FROM accounts WHERE shop_id=? AND name=? ORDER BY id DESC LIMIT 1", Long.class, shopId, req.name);

        BigDecimal opening = req.openingBalance == null ? BigDecimal.ZERO : req.openingBalance.setScale(2, java.math.RoundingMode.HALF_UP);
        if (opening.compareTo(BigDecimal.ZERO) != 0) {
            java.sql.Timestamp now = new java.sql.Timestamp(System.currentTimeMillis());
            // other_transactions
            String otType = opening.compareTo(BigDecimal.ZERO) > 0 ? "income" : "expense";
            BigDecimal amt = opening.abs();
            jdbcTemplate.update("INSERT INTO other_transactions (shop_id,user_id,type,category,counterparty_type,counterparty_id,account_id,amount,tx_time,remark,created_at,updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,NOW(),NOW())",
                    shopId, userId, otType, "account_operation", null, null, id, amt, now, "期初余额");
            // payments
            String direction = opening.compareTo(BigDecimal.ZERO) > 0 ? "in" : "out";
            jdbcTemplate.update("INSERT INTO payments (shop_id,user_id,biz_type,biz_id,account_id,direction,amount,pay_time,remark,created_at) VALUES (?,?,?,?,?,?,?,?,?,NOW())",
                    shopId, userId, "other", null, id, direction, amt, now, "期初余额");
            // update balance
            BigDecimal delta = opening;
            jdbcTemplate.update("UPDATE accounts SET balance = balance + ?, updated_at=NOW() WHERE id=? AND shop_id=?", delta, id, shopId);
        }

        return id;
    }

    @Transactional
    public void update(Long id, Long shopId, Long userId, AccountDtos.CreateAccountRequest req) {
        StringBuilder sql = new StringBuilder("UPDATE accounts SET updated_at=NOW()");
        java.util.List<Object> ps = new java.util.ArrayList<>();
        if (req.name != null) { sql.append(", name=?"); ps.add(req.name); }
        if (req.type != null) { sql.append(", type=?"); ps.add(req.type.toLowerCase()); }
        if (req.bankName != null) { sql.append(", bank_name=?"); ps.add(req.bankName); }
        if (req.bankAccount != null) { sql.append(", bank_account=?"); ps.add(req.bankAccount); }
        if (req.status != null) { sql.append(", status=?"); ps.add(req.status); }
        sql.append(" WHERE id=? AND shop_id=?"); ps.add(id); ps.add(shopId);
        jdbcTemplate.update(sql.toString(), ps.toArray());
    }

    public Map<String,Object> ledger(Long accountId, Long shopId, String kw, int page, int size, String startDate, String endDate) {
        // 汇总
        String baseCond = " shop_id=? AND account_id=?";
        java.util.List<Object> basePs = new java.util.ArrayList<>(); basePs.add(shopId); basePs.add(accountId);
        java.util.function.BiFunction<String, java.util.List<Object>, java.math.BigDecimal> sum = (sql, ps) -> {
            java.math.BigDecimal v = jdbcTemplate.queryForObject(sql, java.math.BigDecimal.class, ps.toArray());
            return v == null ? java.math.BigDecimal.ZERO : v;
        };
        String dateStart = (startDate == null || startDate.isBlank()) ? null : startDate;
        String dateEnd = (endDate == null || endDate.isBlank()) ? null : endDate;

        // opening = 截止开始日期前净额
        String payOpenSql = "SELECT COALESCE(SUM(CASE WHEN direction='in' THEN amount ELSE -amount END),0) FROM payments WHERE" + baseCond + (dateStart==null?"":" AND pay_time<?");
        java.util.List<Object> payOpenPs = new java.util.ArrayList<>(basePs);
        if (dateStart!=null) payOpenPs.add(java.sql.Timestamp.valueOf(dateStart + " 00:00:00"));
        String otOpenSql = "SELECT COALESCE(SUM(CASE WHEN type='income' THEN amount ELSE -amount END),0) FROM other_transactions WHERE" + baseCond + (dateStart==null?"":" AND tx_time<?");
        java.util.List<Object> otOpenPs = new java.util.ArrayList<>(basePs);
        if (dateStart!=null) otOpenPs.add(java.sql.Timestamp.valueOf(dateStart + " 00:00:00"));
        java.math.BigDecimal opening = sum.apply(payOpenSql, payOpenPs).add(sum.apply(otOpenSql, otOpenPs));

        // 区间收入/支出（含两表）
        String payRangeSql = "SELECT COALESCE(SUM(CASE WHEN direction='in' THEN amount ELSE 0 END),0), COALESCE(SUM(CASE WHEN direction='out' THEN amount ELSE 0 END),0) FROM payments WHERE" + baseCond +
                (dateStart==null?"":" AND pay_time>=?") + (dateEnd==null?"":" AND pay_time<=?");
        java.util.List<Object> payRangePs = new java.util.ArrayList<>(basePs);
        if (dateStart!=null) payRangePs.add(java.sql.Timestamp.valueOf(dateStart + " 00:00:00"));
        if (dateEnd!=null) payRangePs.add(java.sql.Timestamp.valueOf(dateEnd + " 23:59:59"));
        java.util.Map<String, Object> pr = jdbcTemplate.queryForMap(payRangeSql, payRangePs.toArray());
        java.math.BigDecimal payIn = (java.math.BigDecimal) pr.values().toArray()[0];
        java.math.BigDecimal payOut = (java.math.BigDecimal) pr.values().toArray()[1];

        String otRangeSql = "SELECT COALESCE(SUM(CASE WHEN type='income' THEN amount ELSE 0 END),0), COALESCE(SUM(CASE WHEN type='expense' THEN amount ELSE 0 END),0) FROM other_transactions WHERE" + baseCond +
                (dateStart==null?"":" AND tx_time>=?") + (dateEnd==null?"":" AND tx_time<=?");
        java.util.List<Object> otRangePs = new java.util.ArrayList<>(basePs);
        if (dateStart!=null) otRangePs.add(java.sql.Timestamp.valueOf(dateStart + " 00:00:00"));
        if (dateEnd!=null) otRangePs.add(java.sql.Timestamp.valueOf(dateEnd + " 23:59:59"));
        java.util.Map<String, Object> or = jdbcTemplate.queryForMap(otRangeSql, otRangePs.toArray());
        java.math.BigDecimal otIn = (java.math.BigDecimal) or.values().toArray()[0];
        java.math.BigDecimal otOut = (java.math.BigDecimal) or.values().toArray()[1];

        java.math.BigDecimal income = payIn.add(otIn);
        java.math.BigDecimal expense = payOut.add(otOut);
        java.math.BigDecimal ending = opening.add(income).subtract(expense);

        // 明细列表（合并两表，按时间倒序）
        String listSql = "SELECT id, biz_type AS src, pay_time AS tx_time, direction, amount, remark, biz_id, NULL AS category FROM payments WHERE" + baseCond +
                (dateStart==null?"":" AND pay_time>=?") + (dateEnd==null?"":" AND pay_time<=?") +
                " UNION ALL " +
                "SELECT id, 'other' AS src, tx_time, CASE WHEN type='income' THEN 'in' ELSE 'out' END AS direction, amount, remark, NULL AS biz_id, category FROM other_transactions WHERE" + baseCond +
                (dateStart==null?"":" AND tx_time>=?") + (dateEnd==null?"":" AND tx_time<=?") +
                " ORDER BY tx_time DESC LIMIT ? OFFSET ?";
        java.util.List<Object> lp = new java.util.ArrayList<>(basePs);
        if (dateStart!=null) { lp.add(java.sql.Timestamp.valueOf(dateStart + " 00:00:00")); }
        if (dateEnd!=null) { lp.add(java.sql.Timestamp.valueOf(dateEnd + " 23:59:59")); }
        if (dateStart!=null) { lp.add(java.sql.Timestamp.valueOf(dateStart + " 00:00:00")); }
        if (dateEnd!=null) { lp.add(java.sql.Timestamp.valueOf(dateEnd + " 23:59:59")); }
        lp.add(size); lp.add(page * size);
        List<Map<String,Object>> list = jdbcTemplate.queryForList(listSql, lp.toArray());

        Map<String,Object> resp = new HashMap<>();
        resp.put("opening", opening);
        resp.put("income", income);
        resp.put("expense", expense);
        resp.put("ending", ending);
        resp.put("list", list);
        return resp;
    }
}


