package com.bizcare.agent;

import jakarta.persistence.EntityManager;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.CommandLineRunner;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.YearMonth;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

@Component
@RequiredArgsConstructor
class DataInitializer implements CommandLineRunner {
    private final EntityManager em;
    private final PasswordEncoder encoder;

    @Override
    @Transactional
    public void run(String... args) {
        if (em.createQuery("select m from Member m where m.userid='demo'", Member.class).getResultList().isEmpty()) {
            seedAll();
        }
        seedUsimLedgersIfEmpty();
        seedStockHistoryIfEmpty();
        seedIndocsEnrich();
        seedReturnsEnrich();
        seedBalancesIfEmpty();
        seedOpenAdjustFields();
        seedUnitCostsIfEmpty();
        seedHomeSalesIfEmpty();
        seedCareHomesIfEmpty();
        seedHomeIndocsIfEmpty();
        seedOpenExchangesIfEmpty();
        seedOpenNameChangesIfEmpty();
        seedOpenWithdrawalsIfEmpty();
        seedOpenSettleHistoriesIfEmpty();
        seedOpenDeleteHistoriesIfEmpty();
        seedBbsNoticeBoardIfEmpty();
        seedBbsPolicyBoardIfEmpty();
        seedBbsPdsBoardIfEmpty();
        seedBoardGroupsIfEmpty();
        seedScansEnrich();
        seedSettlementDocsIfEmpty();
        seedOutcompanyAccountsIfEmpty();
        seedAgentShopSettingIfEmpty();
        seedOpenStatsDemo();
        seedFareboxSamplesIfEmpty();
        seedFareboxPaymentsIfEmpty();
        seedSmsHistoryIfEmpty();
        seedSmsAddressIfEmpty();
        seedStaffMembersIfEmpty();
        seedHomesMembersEnrich();
        seedIncompaniesIfEmpty();
        seedOutcompaniesEnrich();
        seedDeliveriesIfEmpty();
        seedPreferenceIfEmpty();
        seedCsNoticesIfEmpty();
        seedCsInquiriesIfEmpty();
        seedInternalBoardIfEmpty();
        seedScheduleSampleIfEmpty();
        seedPostitsIfEmpty();
        seedStockInfoSampleIfEmpty();
    }

    private void seedStockInfoSampleIfEmpty() {
        Long exists = em.createQuery("select count(s) from Stock s where s.groupId='demo' and s.serial='0018987'", Long.class).getSingleResult();
        if (exists != null && exists > 0) return;

        Company in = em.createQuery("select c from Company c where c.groupId='demo' and c.name like '%CJ헬로%'", Company.class)
            .setMaxResults(1).getResultList().stream().findFirst().orElse(null);
        if (in == null) {
            in = new Company();
            in.setGroupId("demo");
            in.setType("IN");
            in.setName("CJ헬로(SKT)");
            in.setManagerName("CJ담당");
            in.setPhone("02-0000-0000");
            in.setTelecom("SKT");
            in.setActive(true);
            em.persist(in);
            em.flush();
        }
        Company out = em.createQuery("select c from Company c where c.groupId='demo' and c.name='늘푸른통신'", Company.class)
            .setMaxResults(1).getResultList().stream().findFirst().orElse(null);
        if (out == null) {
            out = new Company();
            out.setGroupId("demo");
            out.setType("OUT");
            out.setName("늘푸른통신");
            out.setManagerName("박총괄");
            out.setPhone("010-1111-1003");
            out.setCategory("직영");
            out.setActive(true);
            em.persist(out);
            em.flush();
        } else if (out.getCategory() == null || out.getCategory().isBlank()) {
            out.setCategory("직영");
        }

        LocalDate day = LocalDate.of(2026, 7, 9);
        Stock s = new Stock();
        s.setGroupId("demo");
        s.setGubun("태블릿");
        s.setTelecom("SKT");
        s.setTelcompany("LG헬로비전");
        s.setSerial("0018987");
        s.setBarcode("0018987");
        s.setModel("SM-A175N");
        s.setColor("블랙");
        s.setCond("정상");
        s.setPay("여신");
        s.setState("OUT");
        s.setInprice(new BigDecimal("319000"));
        s.setIncompanyId(in.getId());
        s.setOutcompanyId(out.getId());
        s.setOutCategory("직영");
        s.setIndate(day);
        s.setOutdate(day);
        s.setProcessDate(day);
        s.setProcessor("김대표");
        s.setUserid("demo");
        s.setProcid("demo");
        s.setUid("stk-0018987");
        em.persist(s);
        em.flush();

        StockHistory inHist = new StockHistory();
        inHist.setGroupId("demo");
        inHist.setStockId(s.getId());
        inHist.setIncompanyId(in.getId());
        inHist.setProcessDate(day);
        inHist.setGubun(s.getGubun());
        inHist.setState("IN");
        inHist.setStatusLabel("입고");
        inHist.setSerial(s.getSerial());
        inHist.setModel(s.getModel());
        inHist.setColor(s.getColor());
        inHist.setCond(s.getCond());
        inHist.setProcessor("김대표");
        inHist.setCompanyLabel("");
        em.persist(inHist);

        StockHistory outHist = new StockHistory();
        outHist.setGroupId("demo");
        outHist.setStockId(s.getId());
        outHist.setIncompanyId(in.getId());
        outHist.setOutcompanyId(out.getId());
        outHist.setProcessDate(day);
        outHist.setGubun(s.getGubun());
        outHist.setState("OUT");
        outHist.setStatusLabel("출고");
        outHist.setSerial(s.getSerial());
        outHist.setModel(s.getModel());
        outHist.setColor(s.getColor());
        outHist.setCond(s.getCond());
        outHist.setProcessor("김대표");
        outHist.setCompanyLabel("늘푸른통신 (직영)");
        em.persist(outHist);
    }

    private void seedAll() {
        Company in = company("IN", "입고처A", "김입고", "02-1234-5678");
        Company shop = company("SHOP", "늘붉은통신", "홍길동", "010-1234-5678");
        shop.setBusinessName("늘붉은통신");
        shop.setBankAccount("국민은행 000-000-0000000 홍길동");
        company("DEALER", "데모 딜러", "박딜러", "010-2222-3333");
        Company out = company("OUT", "출고처 샘플", "이출고", "010-4444-5555");
        Company in2 = company("IN", "비즈케어 물류센터", "최물류", "02-5555-1004");
        company("OUT", "D1", "김대리", "010-1111-1001");
        company("OUT", "D2", "이대리", "010-1111-1002");
        company("OUT", "늘푸른통신", "박총괄", "010-1111-1003");
        company("OUT", "스마트모바일", "최영업", "010-1111-1004");
        company("OUT", "블루폰", "정매니저", "010-1111-1005");

        Member agent = new Member();
        agent.setGroupId("demo");
        agent.setUserid("demo");
        agent.setPassword(encoder.encode("demo123"));
        agent.setName("데모 관리자");
        agent.setPhone("010-9999-0000");
        agent.setRole("AGENT");
        agent.setActive(true);
        em.persist(agent);

        Member shopUser = new Member();
        shopUser.setGroupId("demo");
        shopUser.setUserid("demoshop");
        shopUser.setPassword(encoder.encode("demoshop"));
        shopUser.setName("늘붉은통신");
        shopUser.setPhone("010-1234-5678");
        shopUser.setRole("SHOP");
        shopUser.setCompanyId(shop.getId());
        shopUser.setActive(true);
        shopUser.setLoginCount(0);
        shopUser.setPlainPassword("demoshop");
        shopUser.setMenuFlags("{\"policy\":true,\"pds\":true,\"return\":true,\"indoc\":true,\"scan\":true,\"stock\":true,\"open\":true,\"settle\":true,\"farebox\":true}");
        em.persist(shopUser);

        Stock phone = stock("휴대폰", "SKT", "SM-S931N_256G", "아이스블루", "5477154", "OUT", in.getId(), shop.getId(), "1155000");
        Stock tablet = stock("태블릿", "KT", "SM-X910", "그레이", "TAB9001", "IN", in.getId(), null, "900000");
        Stock usim = stock("유심", "SKT", "20044", "공통색상", "10867345", "OUT", in.getId(), shop.getId(), "7700");
        String[] states = {"IN", "OUT", "RETURN", "LOSS", "OPEN", "SELL", "RECOVERY", "RECOVERY", "IN", "OUT", "RECOVERY", "RETURN", "IN", "SELL", "LOSS", "OUT", "RECOVERY"};
        String[] models = {"갤럭시 S25", "아이폰 16 Pro", "갤럭시 A36", "아이폰 16", "갤럭시 Z Flip7", "20044", "갤럭시 S25+", "아이폰 15", "갤럭시 A56"};
        String[] colors = {"티타늄 블루", "블랙", "화이트", "실버", "민트", "공통색상"};
        String[] telecoms = {"SKT", "KT", "LGU+"};
        for (int i = 0; i < states.length; i++) {
            String state = states[i];
            Stock sample = stock(i % 6 == 5 ? "유심" : "휴대폰", telecoms[i % telecoms.length], models[i % models.length],
                    colors[i % colors.length], String.format("SN%010d", 240001 + i), state, i % 2 == 0 ? in.getId() : in2.getId(),
                    state.equals("IN") ? null : (i % 2 == 0 ? shop.getId() : out.getId()), String.valueOf(7700 + i * 85000));
            sample.setPetname(new String[]{"S25특가", "아이폰프로", "보급형", "유심재고"}[i % 4]);
            sample.setOutCategory(i % 2 == 0 ? "판매점" : "도매");
            sample.setSalesperson(new String[]{"김영업", "이영업", "박영업"}[i % 3]);
            sample.setSource(i % 2 == 0 ? "본사" : "온라인");
            sample.setProcessDate(LocalDate.now().minusDays(i % 12));
            sample.setProcessor(new String[]{"데모 관리자", "김대리", "이과장"}[i % 3]);
            sample.setCond(state.equals("RECOVERY") ? "고품" : "정상");
            sample.setMemo(i % 4 == 0 ? "검수 완료" : (state.equals("RECOVERY") ? "회수대기" : null));
            sample.setIndate(LocalDate.now().minusDays(i + 1));
            if (state.equals("RECOVERY")) {
                sample.setOutcompanyId(shop.getId());
                sample.setOutdate(LocalDate.now().minusDays(i + 3));
                sample.setRecalldate(null);
            }
        }

        OpenRecord firstOpen = null;
        String[][] openSamples = {
            {"할부", "SKT", "보상", "김*철", "010-****-5678", "319000", "20000", "5000"},
            {"현금", "KT", "신규", "이*수", "010-****-1234", "450000", "35000", "0"},
            {"유심", "LGU+", "번호이동", "박*영", "010-****-9876", "0", "15000", "0"},
            {"할부", "SKT", "기변", "최*민", "010-****-4321", "890000", "40000", "10000"},
            {"현금", "KT", "메이징", "정*아", "010-****-2468", "120000", "8000", "0"},
            {"할부", "SKT", "가개통", "한*진", "010-****-1357", "550000", "25000", "3000"},
            {"유심", "LGU+", "선불개통", "오*희", "010-****-8642", "0", "5000", "0"},
            {"현금", "SKT", "신규", "윤*호", "010-****-7531", "280000", "18000", "0"},
        };
        for (int i = 0; i < openSamples.length; i++) {
            String[] s = openSamples[i];
            OpenRecord open = new OpenRecord();
            open.setGroupId("demo");
            open.setOutcompanyId(shop.getId());
            open.setIncompanyId(in.getId());
            open.setGubun(s[0]);
            open.setTelecom(s[1]);
            open.setOpenhow(s[2]);
            open.setName(s[3]);
            open.setOpenphone(s[4]);
            open.setOpendate(LocalDate.now().minusDays(i));
            open.setOpenHour(10 + (i % 8));
            open.setOpenMinute(i % 2 == 0 ? 0 : 30);
            open.setOpenStatus("정상");
            open.setOutCategory("판매점");
            open.setSalesperson(i % 2 == 0 ? "김영업" : "이영업");
            open.setEmployee("demo");
            open.setPlan(i % 2 == 0 ? "5GX 프라임" : "LTE 슬림");
            open.setSalemon("할부".equals(s[0]) ? 24 : 0);
            open.setAgreemon(24);
            open.setSalehow(s[0]);
            open.setJoinhow("일반");
            open.setSupportType(i % 3 == 0 ? "선택약정" : "일반");
            open.setPmodel(i % 2 == 0 ? "SM-S928N" : "A2860");
            open.setPserial("할부".equals(s[0]) || "현금".equals(s[0]) ? "IMEI" + (100000 + i) : null);
            open.setPcolor("블랙");
            open.setUserial("유심".equals(s[0]) || i % 2 == 0 ? "USIM" + (200000 + i) : null);
            open.setInprice(new BigDecimal(s[5]));
            open.setNetprice(new BigDecimal(s[5]));
            open.setSellprice(new BigDecimal(s[5]));
            open.setDealermargin1(new BigDecimal(s[6]));
            open.setDeclprice1(new BigDecimal(s[7]));
            open.setCommonSupport(new BigDecimal(i % 2 == 0 ? "300000" : "150000"));
            open.setBasicprice1(new BigDecimal("100000"));
            open.setBasicprice2(new BigDecimal("50000"));
            open.setBasicprice3(new BigDecimal("30000"));
            open.setDecltype(i % 2 == 0 ? "단말할인" : "요금할인");
            open.setState("OPEN");
            open.setUserid("demo");
            open.setUid("open-" + UUID.randomUUID());
            if (i == 0) {
                open.setPhoneStockId(phone.getId());
                open.setPserial(phone.getSerial());
                open.setPmodel(phone.getModel());
                open.setPcolor(phone.getColor());
            }
            em.persist(open);
            if (i == 0) {
                firstOpen = open;
                phone.setOpenId(open.getId());
                phone.setState("OPEN");
            }
        }
        OpenRecord open = firstOpen;

        // shop/policy/pds boards are seeded in dedicated seedBbs* methods

        ScanDoc scan = new ScanDoc();
        scan.setGroupId("demo");
        scan.setOutcompanyId(shop.getId());
        scan.setIncompanyId(in.getId());
        scan.setOutcompanyName(shop.getName());
        scan.setTelcompany("SKT");
        scan.setGubun("보상기변");
        scan.setName("홍길동/010-1234-5678");
        scan.setFilesCount(1);
        scan.setMemo("123456");
        scan.setSendmsg("미비");
        scan.setState("완료");
        scan.setSrc("2");
        scan.setRegisteredAt(java.time.LocalDateTime.now().withHour(13).withMinute(32).withSecond(0).withNano(0));
        em.persist(scan);

        IncompleteDoc indoc = new IncompleteDoc();
        indoc.setGroupId("demo");
        indoc.setOutcompanyId(shop.getId());
        indoc.setIncompanyId(in.getId());
        indoc.setOpenId(open.getId());
        indoc.setOpendate(LocalDate.now());
        indoc.setTelecom("SKT");
        indoc.setCustomerName("김*철");
        indoc.setOpenphone("010-****-5678");
        indoc.setMissingDocs("신분증사본");
        indoc.setDeductAmount(new BigDecimal("30000"));
        indoc.setDeductReason("서류미비");
        indoc.setDeadline(LocalDate.now().plusDays(7));
        indoc.setStatus("미비");
        em.persist(indoc);

        IncompleteDoc indoc2 = new IncompleteDoc();
        indoc2.setGroupId("demo");
        indoc2.setOutcompanyId(shop.getId());
        indoc2.setIncompanyId(in.getId());
        indoc2.setOpendate(LocalDate.now().minusDays(3));
        indoc2.setTelecom("KT");
        indoc2.setCustomerName("이*수");
        indoc2.setOpenphone("010-****-1234");
        indoc2.setMissingDocs("인감증명서, 가족관계증명서");
        indoc2.setDeductAmount(new BigDecimal("50000"));
        indoc2.setDeductReason("추가서류 미제출");
        indoc2.setDeadline(LocalDate.now().plusDays(3));
        indoc2.setStatus("미비");
        em.persist(indoc2);

        IncompleteDoc indoc3 = new IncompleteDoc();
        indoc3.setGroupId("demo");
        indoc3.setOutcompanyId(out.getId());
        indoc3.setIncompanyId(in2.getId());
        indoc3.setOpendate(LocalDate.now().minusDays(10));
        indoc3.setTelecom("LGU+");
        indoc3.setCustomerName("박*영");
        indoc3.setOpenphone("010-****-9876");
        indoc3.setMissingDocs("위임장");
        indoc3.setDeductAmount(new BigDecimal("20000"));
        indoc3.setDeductReason("대리개통 서류");
        indoc3.setDeadline(LocalDate.now().minusDays(1));
        indoc3.setStatus("마감임박");
        em.persist(indoc3);

        UnreturnedPhone ret = new UnreturnedPhone();
        ret.setGroupId("demo");
        ret.setOutcompanyId(shop.getId());
        ret.setIncompanyId(in.getId());
        ret.setOpenId(open.getId());
        ret.setOpendate(LocalDate.now().minusDays(10));
        ret.setTelecom("SKT");
        ret.setCustomerName("이*영");
        ret.setOpenphone("010-****-1111");
        ret.setModel("SM-A175N");
        ret.setSerial("0018987");
        ret.setDeductAmount(new BigDecimal("50000"));
        ret.setReturnStatus("미반납");
        em.persist(ret);

        String[][] returnSamples = {
            {"KT", "박*지", "010-****-6595", "미반납", "A125", "50000", "0"},
            {"SKT", "홍*동", "010-****-2222", "반납", "sm-g220", "1234", "10000"},
            {"LGU+", "김*수", "010-****-3344", "미반납", "SM-S928N", "IMEI9001", "30000"},
            {"SKT", "최*아", "010-****-7788", "반납", "A2860", "SN7788", ""},
            {"KT", "정*호", "010-****-9900", "미반납", "SM-A546", "A5469900", "15000"},
        };
        for (int i = 0; i < returnSamples.length; i++) {
            String[] s = returnSamples[i];
            UnreturnedPhone row = new UnreturnedPhone();
            row.setGroupId("demo");
            row.setOutcompanyId(i % 2 == 0 ? shop.getId() : out.getId());
            row.setIncompanyId(i % 2 == 0 ? in.getId() : in2.getId());
            row.setOpendate(LocalDate.now().minusDays(5 + i * 3));
            row.setTelecom(s[0]);
            row.setCustomerName(s[1]);
            row.setOpenphone(s[2]);
            row.setReturnStatus(s[3]);
            row.setModel(s[4]);
            row.setSerial(s[5]);
            if (!s[6].isBlank()) row.setDeductAmount(new BigDecimal(s[6]));
            if ("반납".equals(s[3])) row.setReturndate(LocalDate.now().minusDays(i));
            em.persist(row);
        }

        SettlementMonth settle = new SettlementMonth();
        settle.setGroupId("demo");
        settle.setOutcompanyId(shop.getId());
        settle.setOutcompanyName(shop.getName());
        settle.setYearMonth(LocalDate.now().toString().substring(0, 7));
        settle.setOpenCount(0);
        settle.setOpenAmount(BigDecimal.ZERO);
        settle.setAfterSettleCount(1);
        settle.setAfterSettleAmount(new BigDecimal("-100000"));
        settle.setHomeProductCount(0);
        settle.setHomeProductAmount(BigDecimal.ZERO);
        settle.setRealSettleAmount(new BigDecimal("-100000"));
        settle.setOutCategory("판매점");
        settle.setStatus("READY");
        settle.setIssued(false);
        settle.setMemo("");
        em.persist(settle);

        Farebox fare = new Farebox();
        fare.setGroupId("demo");
        fare.setOutcompanyId(shop.getId());
        fare.setOutcompanyName(shop.getName());
        fare.setOutCategory("판매점");
        fare.setFaredate(LocalDate.now());
        fare.setTelcompany("SKT");
        fare.setName("홍*동");
        fare.setPhone("010-****-5678");
        fare.setHow("수납");
        fare.setPaystate("완결");
        fare.setCashprice(new BigDecimal("50000"));
        fare.setCardprice(BigDecimal.ZERO);
        fare.setDetail("요금수납");
        fare.setRegistrant("김대표");
        fare.setReceiptNo("R-001");
        em.persist(fare);

        AccountEntry acc = new AccountEntry();
        acc.setGroupId("demo");
        acc.setOutcompanyId(shop.getId());
        acc.setEntryDate(LocalDate.now());
        acc.setType("IN");
        acc.setCategory("정산입금");
        acc.setAmount(new BigDecimal("110000"));
        acc.setMemo("월정산");
        acc.setYearMonth(LocalDate.now().toString().substring(0, 7));
        em.persist(acc);

        for (String telecom : new String[]{"SKT", "KT", "LGU+"}) {
            PlanMaster p = new PlanMaster();
            p.setGroupId("demo");
            p.setTelecom(telecom);
            p.setName(telecom + " 5G 베이직");
            p.setPrice(new BigDecimal("55000"));
            p.setActive(true);
            em.persist(p);
        }

        PhoneModel model = new PhoneModel();
        model.setGroupId("demo");
        model.setTelecom("SKT");
        model.setModelCode("SM-S931N");
        model.setModelName("갤럭시 S25");
        model.setColorOptions("블랙,실버,아이스블루");
        model.setActive(true);
        em.persist(model);

        ScheduleItem schedule = new ScheduleItem();
        schedule.setGroupId("demo");
        schedule.setUserid("demo");
        schedule.setSdate(LocalDate.now());
        schedule.setStime("10:00");
        schedule.setContents("월 정산 확인");
        em.persist(schedule);

        Alim alim = new Alim();
        alim.setGroupId("demo");
        alim.setUserid("demo");
        alim.setTitle("개통 서류 확인");
        alim.setContent("미비 서류를 확인해 주세요.");
        alim.setConfirmed(false);
        em.persist(alim);

        SmsTemplate tpl = new SmsTemplate();
        tpl.setGroupId("demo");
        tpl.setTitle("개통안내");
        tpl.setBody("안녕하세요. 개통이 완료되었습니다.");
        em.persist(tpl);

        CsInquiry cs = new CsInquiry();
        cs.setGroupId("demo");
        cs.setUserid("demo");
        cs.setAuthorName("김대표");
        cs.setTitle("정산 문의");
        cs.setContent("이번달 실정산금 확인 부탁드립니다.");
        cs.setStatus("답변대기");
        cs.setReplyCount(0);
        em.persist(cs);

        Setting setting = new Setting();
        setting.setGroupId("demo");
        setting.setSettingKey("company");
        setting.setValue("{\"name\":\"에이전트 데모\",\"phone\":\"010-0000-0000\",\"managerName\":\"김대표\",\"businessName\":\"에이전트 데모\",\"businessNumber\":\"123-45-67890\",\"ceo\":\"김유신\",\"bizType\":\"도소매\",\"bizItem\":\"휴대폰판매\",\"address\":\"대구시 수성구 수성4가 먼길\"}");
        em.persist(setting);

        tablet.getId();
        usim.getId();
    }

    private void seedUsimLedgersIfEmpty() {
        Map<String, Long> outs = new LinkedHashMap<>();
        for (Company c : em.createQuery("select c from Company c where c.groupId='demo' and c.type in ('OUT','SHOP')", Company.class).getResultList()) {
            outs.put(c.getName(), c.getId());
        }
        for (String name : List.of("D1", "D2", "늘푸른통신", "스마트모바일", "블루폰")) {
            if (outs.containsKey(name)) continue;
            Company c = company("OUT", name, "담당자", "010-0000-0000");
            em.flush();
            outs.put(c.getName(), c.getId());
        }
        if (outs.isEmpty()) return;
        Object[][] samples = {
            {LocalDate.of(2025, 7, 20), "D1", "SKT", 100, "770000", "YENZI", "김대표"},
            {LocalDate.of(2025, 7, 18), "D2", "KT", 50, "385000", "", "정총괄"},
            {LocalDate.of(2025, 7, 15), "늘푸른통신", "LGT", 20, "154000", "333", "김대표"},
            {LocalDate.of(2025, 7, 10), "스마트모바일", "SKT", 5, "38500", "", "이과장"},
            {LocalDate.of(2025, 6, 28), "블루폰", "KT", 8, "61600", "유심일괄", "정총괄"},
            {LocalDate.of(2025, 6, 20), "늘붉은통신", "SK텔링크", 12, "92400", "", "김대표"},
            {LocalDate.of(2025, 6, 12), "출고처 샘플", "SKT", 15, "115500", "프로모션", "데모 관리자"},
            {LocalDate.of(2025, 5, 30), "늘푸른통신", "KT", 10, "77000", "", "정총괄"},
            {LocalDate.of(2025, 5, 22), "D1", "LGT", 7, "53900", "YENZI", "이과장"},
            {LocalDate.of(2025, 5, 10), "D2", "SKT", 25, "192500", "", "김대표"},
            {LocalDate.of(2025, 4, 18), "스마트모바일", "KT", 3, "23100", "333", "정총괄"},
            {LocalDate.of(2025, 4, 5), "블루폰", "LGT", 32, "246400", "", "김대표"},
        };
        for (Object[] s : samples) {
            LocalDate date = (LocalDate) s[0];
            String outName = String.valueOf(s[1]);
            Long outId = outs.get(outName);
            if (outId == null) continue;
            Long exists = em.createQuery(
                "select count(e) from UsimLedger e where e.groupId='demo' and e.tradeDate=:d and e.outcompanyId=:o and e.qty=:q", Long.class)
                .setParameter("d", date).setParameter("o", outId).setParameter("q", (Integer) s[3]).getSingleResult();
            if (exists != null && exists > 0) continue;
            UsimLedger row = new UsimLedger();
            row.setGroupId("demo");
            row.setOutcompanyId(outId);
            row.setTradeDate(date);
            row.setTelecom(String.valueOf(s[2]));
            row.setQty((Integer) s[3]);
            row.setAmount(new BigDecimal(String.valueOf(s[4])));
            String detail = String.valueOf(s[5]);
            row.setDetail(detail.isBlank() ? null : detail);
            row.setRegistrant(String.valueOf(s[6]));
            row.setStatus("정상거래");
            em.persist(row);
        }
    }

    private void seedStockHistoryIfEmpty() {
        Long count = em.createQuery("select count(e) from StockHistory e", Long.class).getSingleResult();
        if (count != null && count > 0) return;
        List<Stock> stocks = em.createQuery("select s from Stock s where s.groupId='demo'", Stock.class).getResultList();
        for (Stock s : stocks) {
            StockHistory h = new StockHistory();
            h.setGroupId("demo");
            h.setStockId(s.getId());
            h.setIncompanyId(s.getIncompanyId());
            h.setOutcompanyId(s.getOutcompanyId());
            h.setProcessDate(s.getProcessDate() != null ? s.getProcessDate() : (s.getIndate() != null ? s.getIndate() : LocalDate.now()));
            h.setGubun(s.getGubun());
            h.setState(s.getState());
            h.setStatusLabel(switch (s.getState() == null ? "" : s.getState()) {
                case "IN" -> "입고";
                case "OUT" -> "출고";
                case "RETURN" -> "반품";
                case "LOSS" -> "분실";
                case "OPEN" -> "개통";
                case "SELL" -> "판매";
                case "RECOVERY" -> "회수대기";
                default -> s.getState();
            });
            h.setSerial(s.getSerial());
            h.setModel(s.getModel());
            h.setColor(s.getColor());
            h.setCond(s.getCond());
            h.setMemo(s.getMemo());
            h.setProcessor(s.getProcessor() != null ? s.getProcessor() : "데모 관리자");
            h.setSalesperson(s.getSalesperson());
            em.persist(h);
            if (s.getIndate() != null && s.getProcessDate() != null && !s.getIndate().equals(s.getProcessDate())) {
                StockHistory in = new StockHistory();
                in.setGroupId("demo");
                in.setStockId(s.getId());
                in.setIncompanyId(s.getIncompanyId());
                in.setProcessDate(s.getIndate());
                in.setGubun(s.getGubun());
                in.setState("IN");
                in.setStatusLabel("입고");
                in.setSerial(s.getSerial());
                in.setModel(s.getModel());
                in.setColor(s.getColor());
                in.setCond(s.getCond());
                in.setProcessor("데모 관리자");
                in.setSalesperson(s.getSalesperson());
                em.persist(in);
            }
        }
    }

    private void seedOpenExchangesIfEmpty() {
        Long count = em.createQuery("select count(e) from OpenExchange e where e.groupId='demo'", Long.class).getSingleResult();
        if (count > 0) return;
        List<Company> shops = em.createQuery("select c from Company c where c.groupId='demo' and c.type in ('SHOP','OUT')", Company.class).getResultList();
        if (shops.isEmpty()) return;
        Object[][] samples = {
            {"단말기", "홍*동", "010-****-5678", "SM-A235N", "블랙", "77777", "SM-A235N", "블랙", "88888", "김처리", "교품완료"},
            {"단말기", "김*수", "010-****-1234", "SM-S911N", "크림", "11111", "SM-S908N", "그린", "22222", "이처리", null},
            {"유심", "박*지", "010-****-9988", "USIM-KT", "-", "U9001", "USIM-KT", "-", "U8001", "demo", "유심교체"},
            {"단말기", "이*호", "010-****-3344", "LM-G820N", "티탄", "33333", "LM-V500N", "화이트", "44444", "최처리", null},
            {"단말기", "최*아", "010-****-5566", "SM-A546S", "라벤더", "55555", "SM-A536S", "어썸블랙", "66666", "김처리", "색상변경"},
            {"유심", "정*민", "010-****-7788", "USIM-SKT", "-", "U7002", "USIM-SKT", "-", "U6002", "demo", null},
            {"단말기", "윤*희", "010-****-1122", "IPHONE15", "블루", "A1001", "IPHONE14", "미드나잇", "A0901", "박처리", null},
            {"단말기", "강*우", "010-****-4455", "SM-F946N", "그레이", "F1001", "SM-F936N", "그린", "F0901", "이처리", "폴드교품"},
            {"단말기", "조*연", "010-****-6677", "SM-A256N", "라이트블루", "A2561", "SM-A245N", "블랙", "A2451", "demo", null},
            {"유심", "한*석", "010-****-8899", "USIM-LGU", "-", "U5003", "USIM-LGU", "-", "U4003", "최처리", null},
            {"단말기", "오*진", "010-****-2211", "SM-S921N", "그레이", "S9211", "SM-S918N", "크림", "S9181", "김처리", null},
            {"단말기", "서*영", "010-****-3434", "LM-Q920N", "오로라", "Q9201", "LM-Q730N", "모로칸블루", "Q7301", "demo", "메모있음"},
            {"단말기", "문*태", "010-****-5656", "SM-A156N", "라이트그레이", "A1561", "SM-A145N", "블랙", "A1451", "박처리", null},
            {"유심", "배*리", "010-****-7878", "USIM-KT", "-", "U3004", "USIM-KT", "-", "U2004", "이처리", null},
            {"단말기", "신*호", "010-****-9090", "SM-G991N", "팬텀그레이", "G9911", "SM-G990N", "화이트", "G9901", "demo", null},
            {"단말기", "유*나", "010-****-1313", "IPHONE13", "핑크", "I1301", "IPHONE12", "퍼플", "I1201", "최처리", "고객요청"},
        };
        for (int i = 0; i < samples.length; i++) {
            Object[] s = samples[i];
            Company shop = shops.get(i % shops.size());
            OpenExchange e = new OpenExchange();
            e.setGroupId("demo");
            e.setOutcompanyId(shop.getId());
            e.setOutcompanyName(shop.getName());
            e.setKind(String.valueOf(s[0]));
            e.setCustomerName(String.valueOf(s[1]));
            e.setOpenphone(String.valueOf(s[2]));
            e.setNewModel(String.valueOf(s[3]));
            e.setNewColor(String.valueOf(s[4]));
            e.setNewSerial(String.valueOf(s[5]));
            e.setOldModel(String.valueOf(s[6]));
            e.setOldColor(String.valueOf(s[7]));
            e.setOldSerial(String.valueOf(s[8]));
            e.setProcessor(String.valueOf(s[9]));
            e.setMemo(s[10] == null ? null : String.valueOf(s[10]));
            e.setExchangeDate(LocalDate.now().minusDays(i));
            e.setOpenDate(LocalDate.now().minusDays(i + 10));
            e.setProcessedAt(java.time.LocalDateTime.now().minusDays(i).withHour(10 + (i % 8)).withMinute((i * 7) % 60).withSecond(0).withNano(0));
            em.persist(e);
        }
    }

    private void seedOpenNameChangesIfEmpty() {
        Long count = em.createQuery("select count(e) from OpenNameChange e where e.groupId='demo'", Long.class).getSingleResult();
        if (count > 0) return;
        List<Company> shops = em.createQuery("select c from Company c where c.groupId='demo' and c.type in ('SHOP','OUT')", Company.class).getResultList();
        if (shops.isEmpty()) return;
        Object[][] samples = {
            {"지*이", "010-****-1234", "김*수", "010-****-9999", "usim (0012345)", "김처리", "명의변경"},
            {"박*지", "010-****-5678", "이*호", "010-****-1111", "-", "이처리", null},
            {"최*아", "010-****-3344", "정*민", "010-****-2222", "usim (0098765)", "demo", null},
            {"윤*희", "010-****-7788", "한*석", "010-****-3333", "-", "최처리", "가족명의"},
            {"강*우", "010-****-5566", "오*진", "010-****-4444", "usim (0054321)", "박처리", null},
            {"조*연", "010-****-9900", "서*영", "010-****-5555", "-", "demo", null},
            {"문*태", "010-****-1122", "배*리", "010-****-6666", "usim (0077001)", "김처리", "법인전환"},
            {"신*호", "010-****-4455", "유*나", "010-****-7777", "-", "이처리", null},
        };
        for (int i = 0; i < samples.length; i++) {
            Object[] s = samples[i];
            Company shop = shops.get(i % shops.size());
            OpenNameChange e = new OpenNameChange();
            e.setGroupId("demo");
            e.setOutcompanyId(shop.getId());
            e.setOutcompanyName(shop.getName());
            e.setCustomerName(String.valueOf(s[0]));
            e.setOpenphone(String.valueOf(s[1]));
            e.setOldOwner(String.valueOf(s[2]));
            e.setOldPhone(String.valueOf(s[3]));
            e.setOldUsim(String.valueOf(s[4]));
            e.setProcessor(String.valueOf(s[5]));
            e.setMemo(s[6] == null ? null : String.valueOf(s[6]));
            e.setChangeDate(LocalDate.now().minusDays(i * 3));
            e.setOpenDate(LocalDate.now().minusDays(i * 3 + 20));
            e.setProcessedAt(java.time.LocalDateTime.now().minusDays(i * 3).withHour(9 + (i % 8)).withMinute((i * 11) % 60).withSecond(0).withNano(0));
            em.persist(e);
        }
    }

    private void seedOpenWithdrawalsIfEmpty() {
        Long count = em.createQuery("select count(e) from OpenWithdrawal e where e.groupId='demo'", Long.class).getSingleResult();
        if (count > 0) return;
        List<Company> shops = em.createQuery("select c from Company c where c.groupId='demo' and c.type in ('SHOP','OUT')", Company.class).getResultList();
        if (shops.isEmpty()) return;
        String[] names = {"김*수", "이*호", "박*지", "최*아", "정*민", "윤*희", "강*우", "조*연", "한*석", "오*진"};
        String[] reasons = {"고객요청", "개통오류", "서류미비", "요금미납", "중복개통", "본인취소", "정책철회", "-"};
        String[] processors = {"김처리", "이처리", "demo", "최처리", "박처리"};
        for (int i = 0; i < 30; i++) {
            Company shop = shops.get(i % shops.size());
            OpenWithdrawal e = new OpenWithdrawal();
            e.setGroupId("demo");
            e.setOutcompanyId(shop.getId());
            e.setOutcompanyName(shop.getName());
            e.setCustomerName(names[i % names.length]);
            e.setOpenphone(String.format("010-****-%04d", 1000 + i * 17));
            e.setProcessor(processors[i % processors.length]);
            e.setReason(reasons[i % reasons.length]);
            e.setWithdrawDate(LocalDate.now().minusDays(i));
            e.setOpenDate(LocalDate.now().minusDays(i + 15));
            e.setProcessedAt(java.time.LocalDateTime.now().minusDays(i).withHour(10 + (i % 8)).withMinute((i * 13) % 60).withSecond(0).withNano(0));
            em.persist(e);
        }
    }

    private void seedOpenSettleHistoriesIfEmpty() {
        Long count = em.createQuery("select count(e) from OpenSettleHistory e where e.groupId='demo'", Long.class).getSingleResult();
        if (count > 0) return;
        List<Company> shops = em.createQuery("select c from Company c where c.groupId='demo' and c.type in ('SHOP','OUT')", Company.class).getResultList();
        if (shops.isEmpty()) return;
        String[] names = {"박*수", "김*한", "이*호", "최*아", "정*민", "윤*희", "강*우", "조*연"};
        String[] processors = {"김대표", "이개통", "demo", "최처리", "박처리"};
        String[] memos = {"정책변경", "단가조정", "추가정산", "차감반영", "재계산", "오류수정"};
        for (int i = 0; i < 40; i++) {
            Company shop = shops.get(i % shops.size());
            long oldAmt = (i % 3 == 0 ? -1 : 1) * (50000L + (i * 17311L) % 300000);
            long newAmt = oldAmt + ((i % 2 == 0 ? 1 : -1) * (10000L + (i * 7919L) % 80000));
            OpenSettleHistory e = new OpenSettleHistory();
            e.setGroupId("demo");
            e.setOutcompanyId(shop.getId());
            e.setOutcompanyName(shop.getName());
            e.setCustomerName(names[i % names.length]);
            e.setOpenphone(String.format("010-****-%04d", 2000 + i * 19));
            e.setOldAmount(BigDecimal.valueOf(oldAmt));
            e.setNewAmount(BigDecimal.valueOf(newAmt));
            e.setProcessor(processors[i % processors.length]);
            e.setMemo(memos[i % memos.length]);
            e.setChangeDate(LocalDate.now().minusDays(i));
            e.setOpenDate(LocalDate.now().minusDays(i + 12));
            e.setProcessedAt(java.time.LocalDateTime.now().minusDays(i).withHour(9 + (i % 9)).withMinute((i * 17) % 60).withSecond(0).withNano(0));
            em.persist(e);
        }
    }

    private void seedOpenDeleteHistoriesIfEmpty() {
        Long count = em.createQuery("select count(e) from OpenDeleteHistory e where e.groupId='demo'", Long.class).getSingleResult();
        if (count > 0) return;
        List<Company> shops = em.createQuery("select c from Company c where c.groupId='demo' and c.type in ('SHOP','OUT')", Company.class).getResultList();
        if (shops.isEmpty()) return;
        Object[][] samples = {
            {"홍***님", "010-****-9870", "정총괄", "개통삭제(변심)"},
            {"a****s", "010-****-1234", "김대표", "개통삭제(출고처수정)"},
            {"홍*동", "010-****-5678", "이개통", "첨부파일삭제(파일명.gif)"},
            {"김*수", "010-****-3344", "demo", "개통삭제(오류)"},
            {"박*지", "010-****-7788", "최처리", "개통삭제(변심)"},
            {"이*호", "010-****-5566", "정총괄", "첨부파일삭제(계약서.pdf)"},
            {"최*아", "010-****-9900", "김대표", "개통삭제(출고처수정)"},
            {"정*민", "010-****-1122", "이개통", "개통삭제(중복)"},
            {"윤*희", "010-****-4455", "demo", "개통삭제(변심)"},
            {"강*우", "010-****-6677", "박처리", "첨부파일삭제(신분증.jpg)"},
            {"조*연", "010-****-8899", "정총괄", "개통삭제(요금미납)"},
            {"한*석", "010-****-2211", "김대표", "개통삭제(변심)"},
            {"오*진", "010-****-3434", "이개통", "개통삭제(출고처수정)"},
            {"서*영", "010-****-5656", "demo", "첨부파일삭제(동의서.png)"},
            {"문*태", "010-****-7878", "최처리", "개통삭제(오류)"},
            {"배*리", "010-****-9090", "정총괄", "개통삭제(변심)"},
        };
        for (int i = 0; i < samples.length; i++) {
            Object[] s = samples[i];
            Company shop = shops.get(i % shops.size());
            OpenDeleteHistory e = new OpenDeleteHistory();
            e.setGroupId("demo");
            e.setOutcompanyId(shop.getId());
            e.setOutcompanyName(shop.getName());
            e.setCustomerName(String.valueOf(s[0]));
            e.setOpenphone(String.valueOf(s[1]));
            e.setProcessor(String.valueOf(s[2]));
            e.setMemo(String.valueOf(s[3]));
            e.setDeleteDate(LocalDate.now().minusDays(i));
            e.setOpenDate(LocalDate.now().minusDays(i + 5));
            e.setProcessedAt(java.time.LocalDateTime.now().minusDays(i).withHour(10 + (i % 8)).withMinute((i * 19) % 60).withSecond(0).withNano(0));
            em.persist(e);
        }
    }

    private void seedBbsNoticeBoardIfEmpty() {
        List<BbsPost> posts = em.createQuery("select b from BbsPost b where b.groupId='demo' and b.code='shop'", BbsPost.class).getResultList();
        Object[][] samples = {
            {"124124", "2020-10-05"},
            {"※ 동행보고 ※ 124123n124 5", "2020-02-17"},
            {"테스트", "2019-04-09"},
        };
        for (Object[] s : samples) {
            String title = String.valueOf(s[0]);
            boolean exists = posts.stream().anyMatch(b -> title.equals(b.getTitle()));
            if (exists) continue;
            BbsPost b = new BbsPost();
            b.setGroupId("demo");
            b.setCode("shop");
            b.setTitle(title);
            b.setContents("<p>" + title + "</p>");
            b.setAuthorName("김대표");
            b.setUserid("demo");
            b.setTargetGroup("전체");
            b.setConfirmCount(2);
            b.setNotice(false);
            b.setViews(0);
            b.setState("1");
            em.persist(b);
        }
        for (BbsPost b : em.createQuery("select b from BbsPost b where b.groupId='demo' and b.code='shop'", BbsPost.class).getResultList()) {
            if (b.getTargetGroup() == null || b.getTargetGroup().isBlank()) b.setTargetGroup("전체");
            if (b.getConfirmCount() == null) b.setConfirmCount(2);
            if (b.getAuthorName() == null || b.getAuthorName().isBlank()) b.setAuthorName("김대표");
        }
    }

    private void seedBbsPolicyBoardIfEmpty() {
        List<BbsPost> posts = em.createQuery("select b from BbsPost b where b.groupId='demo' and b.code='policy'", BbsPost.class).getResultList();
        Object[][] samples = {
            {"31일 1차 단가표", "전체", "김대표", 1},
            {"24124", "전체", "김대표", 3},
            {"124124", "KT", "정총괄", 1},
        };
        for (Object[] s : samples) {
            String title = String.valueOf(s[0]);
            boolean exists = posts.stream().anyMatch(b -> title.equals(b.getTitle()));
            if (exists) continue;
            BbsPost b = new BbsPost();
            b.setGroupId("demo");
            b.setCode("policy");
            b.setTitle(title);
            b.setContents("<p>" + title + "</p>");
            b.setAuthorName(String.valueOf(s[2]));
            b.setUserid("demo");
            b.setTargetGroup(String.valueOf(s[1]));
            b.setConfirmCount(((Number) s[3]).intValue());
            b.setNotice(false);
            b.setViews(0);
            b.setState("1");
            em.persist(b);
        }
        for (BbsPost b : em.createQuery("select b from BbsPost b where b.groupId='demo' and b.code='policy'", BbsPost.class).getResultList()) {
            if (b.getTargetGroup() == null || b.getTargetGroup().isBlank()) b.setTargetGroup("전체");
            if (b.getConfirmCount() == null) b.setConfirmCount(1);
            if (b.getAuthorName() == null || b.getAuthorName().isBlank()) b.setAuthorName("김대표");
        }
    }

    private void seedBbsPdsBoardIfEmpty() {
        List<BbsPost> posts = em.createQuery("select b from BbsPost b where b.groupId='demo' and b.code='pds'", BbsPost.class).getResultList();
        Object[][] samples = {
            {"24124124", "전체", "김대표", 2},
            {"123", "전체", "김대표", 2},
        };
        for (Object[] s : samples) {
            String title = String.valueOf(s[0]);
            boolean exists = posts.stream().anyMatch(b -> title.equals(b.getTitle()));
            if (exists) continue;
            BbsPost b = new BbsPost();
            b.setGroupId("demo");
            b.setCode("pds");
            b.setTitle(title);
            b.setContents("<p>" + title + "</p>");
            b.setAuthorName(String.valueOf(s[2]));
            b.setUserid("demo");
            b.setTargetGroup(String.valueOf(s[1]));
            b.setConfirmCount(((Number) s[3]).intValue());
            b.setNotice(false);
            b.setViews(0);
            b.setState("1");
            em.persist(b);
        }
        for (BbsPost b : em.createQuery("select b from BbsPost b where b.groupId='demo' and b.code='pds'", BbsPost.class).getResultList()) {
            if (b.getTargetGroup() == null || b.getTargetGroup().isBlank()) b.setTargetGroup("전체");
            if (b.getConfirmCount() == null) b.setConfirmCount(2);
            if (b.getAuthorName() == null || b.getAuthorName().isBlank()) b.setAuthorName("김대표");
        }
    }

    private void seedBoardGroupsIfEmpty() {
        Long count = em.createQuery("select count(g) from BoardGroup g where g.groupId='demo'", Long.class).getSingleResult();
        if (count > 0) return;
        List<Company> shops = em.createQuery("select c from Company c where c.groupId='demo' and c.type in ('SHOP','OUT')", Company.class).getResultList();
        String shopIds = shops.stream().map(c -> String.valueOf(c.getId())).collect(java.util.stream.Collectors.joining(","));
        Object[][] samples = {
            {"기본통신사", "LG헬로비전", shopIds},
            {"기본통신사", "KT", shopIds},
            {"기본통신사", "SKT", shopIds},
            {"기본통신사", "LGU+", shopIds.isEmpty() ? "" : shops.getFirst().getId().toString()},
            {"기본통신사", "SK브로드밴드", ""},
            {"사용자그룹", "A그룹", shops.size() < 2 ? shopIds : shops.stream().limit(2).map(c -> String.valueOf(c.getId())).collect(java.util.stream.Collectors.joining(","))},
            {"사용자그룹", "테스트", ""},
            {"사용자그룹", "LG유모비", ""},
            {"사용자그룹", "B그룹", shops.size() > 1 ? shops.get(1).getId().toString() : ""},
            {"사용자그룹", "VIP", ""},
            {"사용자그룹", "도매전용", shops.isEmpty() ? "" : shops.getFirst().getId().toString()},
        };
        for (Object[] s : samples) {
            BoardGroup g = new BoardGroup();
            g.setGroupId("demo");
            g.setCategory(String.valueOf(s[0]));
            g.setName(String.valueOf(s[1]));
            g.setCompanyIds(String.valueOf(s[2]));
            em.persist(g);
        }
    }

    private void seedScansEnrich() {
        List<ScanDoc> scans = em.createQuery("select s from ScanDoc s where s.groupId='demo'", ScanDoc.class).getResultList();
        for (ScanDoc s : scans) {
            if ("DONE".equals(s.getState()) || "DONE".equalsIgnoreCase(String.valueOf(s.getState()))) s.setState("완료");
            if ("PENDING".equals(s.getState())) s.setState("대기");
            if (s.getRegisteredAt() == null) s.setRegisteredAt(s.getCreatedAt() == null ? java.time.LocalDateTime.now() : java.time.LocalDateTime.ofInstant(s.getCreatedAt(), java.time.ZoneId.of("Asia/Seoul")));
            if (s.getOutcompanyName() == null || s.getOutcompanyName().isBlank()) {
                if (s.getOutcompanyId() != null) {
                    Company c = em.find(Company.class, s.getOutcompanyId());
                    if (c != null) s.setOutcompanyName(c.getName());
                }
            }
        }
        if (scans.size() >= 3) return;
        List<Company> shops = em.createQuery("select c from Company c where c.groupId='demo' and c.type in ('SHOP','OUT')", Company.class).getResultList();
        if (shops.isEmpty()) return;
        Company shop = shops.getFirst();
        Object[][] samples = {
            {"완료", "SKT", "보상기변", "비즈케어/010-1234-5678", null, null, 1},
            {"접수", "SKT2", "MNP", "비즈케어", null, null, 1},
        };
        for (int i = 0; i < samples.length; i++) {
            if (scans.size() + i >= 3) break;
            Object[] s = samples[i];
            ScanDoc d = new ScanDoc();
            d.setGroupId("demo");
            d.setOutcompanyId(shop.getId());
            d.setOutcompanyName(shop.getName());
            d.setState(String.valueOf(s[0]));
            d.setTelcompany(String.valueOf(s[1]));
            d.setGubun(String.valueOf(s[2]));
            d.setName(String.valueOf(s[3]));
            d.setSendmsg(s[4] == null ? null : String.valueOf(s[4]));
            d.setMemo(s[5] == null ? null : String.valueOf(s[5]));
            d.setFilesCount(((Number) s[6]).intValue());
            d.setSrc("2");
            d.setRegisteredAt(java.time.LocalDateTime.now().minusDays(i + 1).withHour(12 + i).withMinute(1 + i * 20).withSecond(0).withNano(0));
            em.persist(d);
        }
    }

    private void seedSettlementDocsIfEmpty() {
        String ym = LocalDate.now().minusMonths(1).toString().substring(0, 7);
        Company d2 = em.createQuery("select c from Company c where c.groupId='demo' and c.name='D2'", Company.class)
            .getResultList().stream().findFirst().orElse(null);
        if (d2 == null) {
            d2 = company("OUT", "D2", "이대리", "010-1111-1002");
        }
        List<SettlementMonth> prev = em.createQuery(
            "select s from SettlementMonth s where s.groupId='demo' and s.yearMonth=:y", SettlementMonth.class)
            .setParameter("y", ym).getResultList();
        if (prev.isEmpty()) {
            SettlementMonth s = new SettlementMonth();
            s.setGroupId("demo");
            s.setOutcompanyId(d2.getId());
            s.setOutcompanyName("D2");
            s.setYearMonth(ym);
            s.setOutCategory("판매점");
            s.setOpenCount(0);
            s.setOpenAmount(BigDecimal.ZERO);
            s.setAfterSettleCount(1);
            s.setAfterSettleAmount(new BigDecimal("-100000"));
            s.setHomeProductCount(0);
            s.setHomeProductAmount(BigDecimal.ZERO);
            s.setRealSettleAmount(new BigDecimal("-100000"));
            s.setIssued(false);
            s.setStatus("READY");
            s.setInquiry("-");
            s.setAgreement("-");
            s.setInvoiceStatus("-");
            s.setRemittanceStatus("-");
            em.persist(s);
        } else {
            // Align demo sample with original screenshot (출고처 D2 / 후정산 1 / -100,000)
            SettlementMonth s = prev.getFirst();
            s.setOutcompanyId(d2.getId());
            s.setOutcompanyName("D2");
            s.setOutCategory(s.getOutCategory() == null ? "판매점" : s.getOutCategory());
            if (s.getAfterSettleCount() == null || s.getAfterSettleCount() == 0) s.setAfterSettleCount(1);
            if (s.getAfterSettleAmount() == null || s.getAfterSettleAmount().compareTo(BigDecimal.ZERO) == 0) {
                s.setAfterSettleAmount(new BigDecimal("-100000"));
            }
            if (s.getRealSettleAmount() == null || s.getRealSettleAmount().compareTo(BigDecimal.ZERO) == 0) {
                s.setRealSettleAmount(s.getAfterSettleAmount());
            }
        }

        for (SettlementMonth row : em.createQuery("select s from SettlementMonth s where s.groupId='demo'", SettlementMonth.class).getResultList()) {
            if (row.getOutcompanyName() == null || row.getOutcompanyName().isBlank()) {
                Company c = row.getOutcompanyId() == null ? null : em.find(Company.class, row.getOutcompanyId());
                if (c != null) row.setOutcompanyName(c.getName());
            }
            if (row.getAfterSettleCount() == null) row.setAfterSettleCount(row.getAfterSettleAmount() == null || row.getAfterSettleAmount().compareTo(BigDecimal.ZERO) == 0 ? 0 : 1);
            if (row.getOpenCount() == null) row.setOpenCount(0);
            if (row.getOpenAmount() == null) row.setOpenAmount(BigDecimal.ZERO);
            if (row.getHomeProductCount() == null) row.setHomeProductCount(0);
            if (row.getHomeProductAmount() == null) row.setHomeProductAmount(BigDecimal.ZERO);
            if (row.getInquiry() == null) row.setInquiry("-");
            if (row.getAgreement() == null) row.setAgreement("-");
            if (row.getInvoiceStatus() == null) row.setInvoiceStatus("-");
            if (row.getRemittanceStatus() == null) row.setRemittanceStatus("-");
        }
    }

    private void seedOutcompanyAccountsIfEmpty() {
        String menuAll = "{\"policy\":true,\"pds\":true,\"return\":true,\"indoc\":true,\"scan\":true,\"stock\":true,\"open\":true,\"settle\":true,\"farebox\":true}";
        Object[][] specs = {
            {"대구 D1", "도매", "P0000", "늘명훈", "010-1111-1111", "demoshop", "demoshop", true, 0, null},
            {"대구 늘푸른통신", "도매", "P1234", "김담당", "010-2222-2222", "as001", "as001", true, 89, "2026-07-10T22:10:00"},
            {"경산 D2", "도매", "P2001", "이대리", "010-1111-1002", "d2shop", "d2shop", true, 53, "2026-07-09T18:20:00"},
            {"스마트모바일", "소매", "P3001", "최영업", "010-1111-1004", "smart01", "smart01", false, 12, "2026-06-01T10:00:00"},
            {"블루폰", "C채널", "P4001", "정매니저", "010-1111-1005", null, null, true, 0, null},
            {"출고처 샘플", "특판", "P5001", "이출고", "010-4444-5555", "sample1", "sample1", true, 100, "2026-07-08T09:15:00"},
            {"늘붉은통신", "소매", "P0001", "홍길동", "010-1234-5678", null, null, true, 0, null},
        };
        for (Object[] s : specs) {
            String name = String.valueOf(s[0]);
            Company c = em.createQuery("select c from Company c where c.groupId='demo' and c.name=:n", Company.class)
                .setParameter("n", name).getResultList().stream().findFirst().orElse(null);
            if (c == null && name.endsWith(" D1")) {
                c = em.createQuery("select c from Company c where c.groupId='demo' and c.name='D1'", Company.class)
                    .getResultList().stream().findFirst().orElse(null);
            }
            if (c == null && name.endsWith(" D2")) {
                c = em.createQuery("select c from Company c where c.groupId='demo' and c.name='D2'", Company.class)
                    .getResultList().stream().findFirst().orElse(null);
            }
            if (c == null && name.contains("늘푸른")) {
                c = em.createQuery("select c from Company c where c.groupId='demo' and c.name='늘푸른통신'", Company.class)
                    .getResultList().stream().findFirst().orElse(null);
            }
            if (c == null) {
                String type = "늘붉은통신".equals(name) ? "SHOP" : "OUT";
                c = company(type, name, String.valueOf(s[3]), String.valueOf(s[4]));
            } else {
                c.setName(name);
            }
            c.setChannel(String.valueOf(s[1]));
            c.setPcode(String.valueOf(s[2]));
            c.setManagerName(String.valueOf(s[3]));
            c.setPhone(String.valueOf(s[4]));
            if (s[5] == null) continue;
            String userid = String.valueOf(s[5]);
            String password = String.valueOf(s[6]);
            boolean active = Boolean.TRUE.equals(s[7]);
            int loginCount = ((Number) s[8]).intValue();
            Member m = em.createQuery("select m from Member m where m.groupId='demo' and m.role='SHOP' and m.companyId=:c", Member.class)
                .setParameter("c", c.getId()).getResultList().stream().findFirst().orElse(null);
            if (m == null) {
                List<Member> byUser = em.createQuery("select m from Member m where m.userid=:id", Member.class)
                    .setParameter("id", userid).getResultList();
                if (!byUser.isEmpty()) {
                    m = byUser.getFirst();
                    m.setCompanyId(c.getId());
                    m.setRole("SHOP");
                } else {
                    m = new Member();
                    m.setGroupId("demo");
                    m.setRole("SHOP");
                    m.setCompanyId(c.getId());
                    m.setUserid(userid);
                    m.setPassword(encoder.encode(password));
                    em.persist(m);
                }
            }
            m.setUserid(userid);
            m.setPassword(encoder.encode(password));
            m.setPlainPassword(password);
            m.setName(c.getName());
            m.setPhone(c.getPhone());
            m.setActive(active);
            m.setLoginCount(loginCount);
            m.setMenuFlags(menuAll);
            if (s[9] != null) m.setLastLoginAt(java.time.LocalDateTime.parse(String.valueOf(s[9])));
        }
        for (Company c : em.createQuery("select c from Company c where c.groupId='demo' and c.type in ('OUT','SHOP')", Company.class).getResultList()) {
            if (c.getChannel() == null || c.getChannel().isBlank()) c.setChannel("기타");
            if (c.getPcode() == null || c.getPcode().isBlank()) c.setPcode("P" + String.format("%04d", c.getId() == null ? 0 : c.getId()));
        }
        for (Member m : em.createQuery("select m from Member m where m.groupId='demo' and m.role='SHOP'", Member.class).getResultList()) {
            if ((m.getPlainPassword() == null || m.getPlainPassword().isBlank()) && "demoshop".equals(m.getUserid())) {
                m.setPlainPassword("demoshop");
            }
            if (m.getMenuFlags() == null || m.getMenuFlags().isBlank()) m.setMenuFlags(menuAll);
            if (m.getLoginCount() == null) m.setLoginCount(0);
        }
    }

    private void seedAgentShopSettingIfEmpty() {
        Long count = em.createQuery("select count(s) from Setting s where s.groupId='demo' and s.settingKey='agentshop'", Long.class).getSingleResult();
        if (count != null && count > 0) return;
        Setting s = new Setting();
        s.setGroupId("demo");
        s.setSettingKey("agentshop");
        s.setValue("{\"access\":true,\"policy\":true,\"pds\":true,\"returnPhone\":true,\"indoc\":true,\"scan\":true,\"scanReceiveSms\":false,\"scanReceivePhones\":\"\",\"scanSendSms\":false,\"scanSenderPhone\":\"1600-3903\",\"scanCompleteMsg\":\"스캔신청서가 완료 처리되었습니다.\",\"scanHoldMsg\":\"스캔신청서가 보류 처리되었습니다.\",\"stock\":true,\"stockPeriod\":\"always\",\"open\":true,\"settle\":true,\"farebox\":true,\"shopUrl\":\"https://shop.bizcare.co.kr\"}");
        em.persist(s);
    }

    private void seedFareboxSamplesIfEmpty() {
        Long count = em.createQuery("select count(e) from Farebox e where e.groupId='demo'", Long.class).getSingleResult();
        if (count != null && count >= 6) return;
        List<Company> shops = em.createQuery("select c from Company c where c.groupId='demo' and c.type in ('SHOP','OUT') order by c.id", Company.class).getResultList();
        if (shops.isEmpty()) return;
        Object[][] samples = {
            {LocalDate.of(2025, 11, 16), "SKT", "대박통신", "김*현", "010-****-5555", "수납", "0", "12200", "완결", "", "김대표"},
            {LocalDate.of(2025, 5, 22), "SKT", "늘푸른통신", "1*3", "***-****-****", "수납", "653000", "0", "미결", "", "김대표"},
            {LocalDate.of(2025, 4, 10), "KT엠모바일", "늘푸른통신", "최***신", "010-****-1111", "수납", "20000", "0", "완결", "선불충전", "김대표"},
            {LocalDate.of(2025, 3, 8), "LGT", "테스트", "홍*동", "010-****-2222", "대납", "-20000", "0", "미결", "환불금", "김대표"},
            {LocalDate.of(2025, 2, 1), "SK텔링크", shops.getFirst().getName(), "박*수", "010-****-3333", "수납", "0", "50000", "완결", "요금수납", "김대표"},
        };
        for (int i = 0; i < samples.length; i++) {
            Object[] s = samples[i];
            LocalDate date = (LocalDate) s[0];
            String name = String.valueOf(s[3]);
            Long exists = em.createQuery("select count(e) from Farebox e where e.groupId='demo' and e.faredate=:d and e.name=:n", Long.class)
                .setParameter("d", date).setParameter("n", name).getSingleResult();
            if (exists != null && exists > 0) continue;
            Company shop = shops.get(i % shops.size());
            Farebox row = new Farebox();
            row.setGroupId("demo");
            row.setOutcompanyId(shop.getId());
            row.setOutcompanyName(String.valueOf(s[2]));
            row.setOutCategory("판매점");
            row.setFaredate(date);
            row.setTelcompany(String.valueOf(s[1]));
            row.setName(name);
            row.setPhone(String.valueOf(s[4]));
            row.setHow(String.valueOf(s[5]));
            row.setCashprice(new BigDecimal(String.valueOf(s[6])));
            row.setCardprice(new BigDecimal(String.valueOf(s[7])));
            row.setPaystate(String.valueOf(s[8]));
            row.setDetail(String.valueOf(s[9]));
            row.setRegistrant(String.valueOf(s[10]));
            row.setReceiptNo("R-S" + (i + 1));
            em.persist(row);
        }
    }

    private void seedFareboxPaymentsIfEmpty() {
        Long count = em.createQuery("select count(p) from FareboxPayment p where p.groupId='demo'", Long.class).getSingleResult();
        if (count != null && count >= 8) return;
        List<Farebox> boxes = em.createQuery("select e from Farebox e where e.groupId='demo' order by e.id", Farebox.class).getResultList();
        Object[][] samples = {
            {LocalDate.of(2025, 7, 12), "늘푸른통신", "일반", "653000", "이계통", "정상", "판매점"},
            {LocalDate.of(2025, 7, 10), "D1", "건별", "2500", "재고전용", "정상", "판매점"},
            {LocalDate.of(2025, 6, 20), "대박통신", "일반", "12200", "김대표", "취소됨", "판매점"},
            {LocalDate.of(2025, 5, 15), "늘푸른통신", "건별", "20000", "이계통", "정상", "판매점"},
            {LocalDate.of(2025, 4, 8), "테스트", "일반", "50000", "김대표", "정상", "판매점"},
            {LocalDate.of(2025, 3, 22), "늘붉은통신", "일반", "30000", "재고전용", "정상", "판매점"},
            {LocalDate.of(2025, 2, 14), "대박통신", "건별", "15000", "이계통", "취소됨", "판매점"},
            {LocalDate.of(2025, 1, 5), "D1", "일반", "8800", "김대표", "정상", "판매점"},
        };
        for (int i = 0; i < samples.length; i++) {
            Object[] s = samples[i];
            LocalDate paydate = (LocalDate) s[0];
            String outName = String.valueOf(s[1]);
            Long exists = em.createQuery(
                "select count(p) from FareboxPayment p where p.groupId='demo' and p.paydate=:d and p.outcompanyName=:n and p.amount=:a", Long.class)
                .setParameter("d", paydate).setParameter("n", outName).setParameter("a", new BigDecimal(String.valueOf(s[3])))
                .getSingleResult();
            if (exists != null && exists > 0) continue;
            FareboxPayment p = new FareboxPayment();
            p.setGroupId("demo");
            p.setPaydate(paydate);
            p.setOutcompanyName(outName);
            p.setMode(String.valueOf(s[2]));
            p.setAmount(new BigDecimal(String.valueOf(s[3])));
            p.setRegistrant(String.valueOf(s[4]));
            p.setStatus(String.valueOf(s[5]));
            p.setOutCategory(String.valueOf(s[6]));
            p.setPayCount(1);
            p.setMemo(null);
            if (!boxes.isEmpty()) {
                Farebox box = boxes.get(i % boxes.size());
                p.setOutcompanyId(box.getOutcompanyId());
                p.setFareboxIds(String.valueOf(box.getId()));
            }
            em.persist(p);
        }
    }

    private void seedSmsHistoryIfEmpty() {
        Long balCount = em.createQuery("select count(s) from Setting s where s.groupId='demo' and s.settingKey='sms_balance'", Long.class).getSingleResult();
        if (balCount == null || balCount == 0) {
            Setting bal = new Setting();
            bal.setGroupId("demo");
            bal.setSettingKey("sms_balance");
            bal.setValue("996");
            em.persist(bal);
        }
        Long count = em.createQuery("select count(e) from SmsMessage e where e.groupId='demo'", Long.class).getSingleResult();
        if (count != null && count >= 4) return;
        Object[][] samples = {
            {LocalDateTime.of(2026, 7, 10, 13, 40), "01011111111", "단문", "안녕하세요. 비즈케어 안내 문자입니다.", "김대표"},
            {LocalDateTime.of(2026, 7, 9, 10, 15), "01022222222", "단문", "개통 서류 안내드립니다.", "이계통"},
            {LocalDateTime.of(2026, 7, 8, 16, 5), "01033334444,01055556666", "단문", "유심 수령 안내입니다.", "김대표"},
            {LocalDateTime.of(2026, 7, 7, 9, 30), "01077778888", "단문", "요금수납 확인 부탁드립니다.", "이계통"},
        };
        for (Object[] s : samples) {
            LocalDateTime ldt = (LocalDateTime) s[0];
            String phone = String.valueOf(s[1]);
            Long exists = em.createQuery(
                "select count(e) from SmsMessage e where e.groupId='demo' and e.phone=:p and e.message=:m", Long.class)
                .setParameter("p", phone).setParameter("m", String.valueOf(s[3])).getSingleResult();
            if (exists != null && exists > 0) continue;
            int sendCount = phone.split(",").length;
            SmsMessage row = new SmsMessage();
            row.setGroupId("demo");
            row.setUserid("demo");
            row.setPhone(phone);
            row.setMessage(String.valueOf(s[3]));
            row.setStatus("발송");
            row.setMsgType(String.valueOf(s[2]));
            row.setSenderNumber("1600-3903");
            row.setSenderName(String.valueOf(s[4]));
            row.setSendCount(sendCount);
            row.setDeductCount(sendCount);
            row.setSentAt(ldt.atZone(ZoneId.systemDefault()).toInstant());
            em.persist(row);
        }
    }

    private void seedSmsAddressIfEmpty() {
        Long gCount = em.createQuery("select count(g) from SmsAddressGroup g where g.groupId='demo'", Long.class).getSingleResult();
        if (gCount != null && gCount > 0) return;
        SmsAddressGroup g1 = new SmsAddressGroup();
        g1.setGroupId("demo");
        g1.setName("동해물과");
        em.persist(g1);
        em.flush();
        SmsAddressGroup g2 = new SmsAddressGroup();
        g2.setGroupId("demo");
        g2.setName("백두산이");
        em.persist(g2);
        Object[][] contacts = {
            {g1.getId(), "1", "01000000000"},
            {g1.getId(), "홍길동", "01015231244"},
        };
        for (Object[] s : contacts) {
            SmsAddressContact c = new SmsAddressContact();
            c.setGroupId("demo");
            c.setAddressGroupId((Long) s[0]);
            c.setName(String.valueOf(s[1]));
            c.setPhone(String.valueOf(s[2]));
            em.persist(c);
        }
    }

    private void seedStaffMembersIfEmpty() {
        // enrich demo owner
        List<Member> demos = em.createQuery("select m from Member m where m.userid='demo'", Member.class).getResultList();
        if (!demos.isEmpty()) {
            Member demo = demos.getFirst();
            if (demo.getStaffPermission() == null || demo.getStaffPermission().isBlank()) {
                demo.setStaffPermission("대표");
                demo.setName("김대표");
                demo.setPhone("010-1111-2222");
                if (demo.getLoginCount() == null || demo.getLoginCount() == 0) demo.setLoginCount(5032);
                if (demo.getLastLoginAt() == null) demo.setLastLoginAt(LocalDateTime.now().minusMinutes(10));
                if (demo.getAssignedOutNames() == null) demo.setAssignedOutNames("늘푸른통신,대박통신");
            }
        }
        Long count = em.createQuery("select count(m) from Member m where m.groupId='demo' and m.role='AGENT'", Long.class).getSingleResult();
        if (count != null && count >= 8) return;
        Object[][] samples = {
            {"demo02", "이총괄", "총괄", "010-2222-3333", "D1,D2", 1204},
            {"demo03", "박재고", "재고", "010-3333-4444", "늘푸른통신", 856},
            {"demo04", "최개통", "개통", "010-4444-5555", "스마트모바일,블루폰", 642},
            {"demo05", "정영업", "영업", "010-5555-6666", "대박통신", 311},
            {"demo06", "한딜러", "딜러", "010-6666-7777", "출고처 샘플", 98},
            {"demo07", "오재고", "재고", "010-7777-8888", "", 45},
            {"demo08", "윤영업", "영업", "010-8888-9999", "늘붉은통신", 22},
            {"demo09", "강총괄", "총괄", "010-9999-1111", "D1", 15},
            {"demo10", "조개통", "개통", "010-1212-3434", "", 8},
            {"demo11", "임영업", "영업", "010-5656-7878", "블루폰", 3},
            {"demo12", "배수납", "영업", "010-9090-1212", "스마트모바일", 1},
        };
        for (int i = 0; i < samples.length; i++) {
            Object[] s = samples[i];
            String userid = String.valueOf(s[0]);
            Long exists = em.createQuery("select count(m) from Member m where m.userid=:id", Long.class)
                .setParameter("id", userid).getSingleResult();
            if (exists != null && exists > 0) continue;
            Member m = new Member();
            m.setGroupId("demo");
            m.setUserid(userid);
            m.setPassword(encoder.encode("demo123"));
            m.setPlainPassword("demo123");
            m.setName(String.valueOf(s[1]));
            m.setStaffPermission(String.valueOf(s[2]));
            m.setPhone(String.valueOf(s[3]));
            String outs = String.valueOf(s[4]);
            m.setAssignedOutNames(outs.isBlank() ? null : outs);
            m.setRole("AGENT");
            m.setActive(true);
            m.setLoginCount((Integer) s[5]);
            m.setLastLoginAt(LocalDateTime.now().minusDays(i).minusHours(i % 5));
            em.persist(m);
        }
    }

    private void seedHomesMembersEnrich() {
        // 홈즈 직원관리 원본 샘플 (대표 + demo1~5)
        Object[][] samples = {
            {"demo", "홍길동", "대표", "010-1234-1234", "대구광역시 동구 동대구로455", "", 205,
                    LocalDateTime.of(2026, 7, 11, 17, 53), LocalDate.of(2022, 4, 12), "데모 대표계정"},
            {"demo1", "홍총괄", "총괄", "010-1111-1111", "1", "", 6,
                    LocalDateTime.of(2022, 4, 13, 12, 33), LocalDate.of(2022, 4, 13), null},
            {"demo2", "홍팀장", "팀장", "010-2222-2222", "", "", 3,
                    LocalDateTime.of(2022, 4, 14, 10, 12), LocalDate.of(2022, 4, 13), null},
            {"demo3", "홍사원", "사원", "010-3333-3333", "", "", 2,
                    LocalDateTime.of(2022, 4, 13, 16, 36), LocalDate.of(2022, 4, 13), null},
            {"demo4", "홍영업", "영업", "010-4444-4444", "", "", 3,
                    LocalDateTime.of(2022, 4, 13, 16, 42), LocalDate.of(2022, 4, 13), null},
            {"demo5", "홍딜러", "딜러", "010-5555-5555", "", "", 1,
                    LocalDateTime.of(2022, 4, 13, 16, 49), LocalDate.of(2022, 4, 13), null},
        };
        java.util.Set<String> keep = new java.util.HashSet<>();
        for (Object[] s : samples) keep.add(String.valueOf(s[0]));
        for (Member old : em.createQuery("select m from Member m where m.groupId='demo' and m.role='AGENT'", Member.class).getResultList()) {
            if (!keep.contains(old.getUserid())) em.remove(old);
        }
        em.flush();
        for (Object[] s : samples) {
            String userid = String.valueOf(s[0]);
            List<Member> found = em.createQuery("select m from Member m where m.userid=:id", Member.class)
                    .setParameter("id", userid).getResultList();
            Member m = found.isEmpty() ? new Member() : found.getFirst();
            m.setGroupId("demo");
            m.setUserid(userid);
            m.setName(String.valueOf(s[1]));
            m.setStaffPermission(String.valueOf(s[2]));
            m.setPhone(String.valueOf(s[3]));
            String addr = String.valueOf(s[4]);
            m.setAddress(addr.isBlank() ? null : addr);
            String limit = String.valueOf(s[5]);
            m.setAccessLimit(limit.isBlank() ? null : limit);
            m.setLoginCount((Integer) s[6]);
            m.setLastLoginAt((LocalDateTime) s[7]);
            m.setRole("AGENT");
            m.setActive(true);
            if (s[9] != null) m.setMemo(String.valueOf(s[9]));
            if (found.isEmpty()) {
                m.setPassword(encoder.encode("demo123"));
                m.setPlainPassword("demo123");
                em.persist(m);
                em.flush();
            }
            LocalDate reg = (LocalDate) s[8];
            if (reg != null) {
                Instant at = reg.atStartOfDay(ZoneId.of("Asia/Seoul")).toInstant();
                m.setCreatedAt(at);
                m.setUpdatedAt(at);
            }
        }
    }

    private void seedIncompaniesIfEmpty() {
        Long count = em.createQuery("select count(c) from Company c where c.groupId='demo' and c.type='IN'", Long.class).getSingleResult();
        Object[][] samples = {
            {"디엘로(KT)", "LG헬로비전 (KT)", "02-0000-0000", "02-0000-0001", "우담당", "010-0000-0000", "디헬로우", "000-00-00000"},
            {"KT", "KT", "02-1111-1111", "02-1111-1112", "김담당", "010-1111-1111", "케이티", "111-11-11111"},
            {"SKT", "SKT", "02-2222-2222", "02-2222-2223", "이담당", "010-2222-2222", "에스케이티", "222-22-22222"},
            {"LGU+", "LGU+", "02-3333-3333", "", "박담당", "010-3333-3333", "엘지유플러스", "333-33-33333"},
            {"SK텔링크", "SK텔링크", "02-4444-4444", "", "최담당", "010-4444-4444", "텔링크", "444-44-44444"},
            {"KT엠모바일", "KT엠모바일", "02-5555-5555", "", "정담당", "010-5555-5555", "엠모바일", "555-55-55555"},
            {"비즈케어 물류센터", "SKT", "02-5555-1004", "02-5555-1005", "최물류", "010-5555-1004", "비즈케어물류", "666-66-66666"},
            {"입고처A", "KT", "02-1234-5678", "", "김입고", "010-1234-5678", "입고에이", "777-77-77777"},
        };
        if (count != null && count >= 8) {
            // enrich existing IN companies missing telecom
            List<Company> existing = em.createQuery("select c from Company c where c.groupId='demo' and c.type='IN'", Company.class).getResultList();
            for (Company c : existing) {
                if (c.getTelecom() == null || c.getTelecom().isBlank()) {
                    for (Object[] s : samples) {
                        if (String.valueOf(s[0]).equals(c.getName())) {
                            c.setTelecom(String.valueOf(s[1]));
                            c.setFax(blankStr(String.valueOf(s[3])));
                            c.setMobile(String.valueOf(s[5]));
                            c.setBusinessName(String.valueOf(s[6]));
                            c.setBusinessNumber(String.valueOf(s[7]));
                            break;
                        }
                    }
                    if (c.getTelecom() == null || c.getTelecom().isBlank()) c.setTelecom("SKT");
                }
            }
            return;
        }
        for (Object[] s : samples) {
            String name = String.valueOf(s[0]);
            Long exists = em.createQuery("select count(c) from Company c where c.groupId='demo' and c.type='IN' and c.name=:n", Long.class)
                .setParameter("n", name).getSingleResult();
            if (exists != null && exists > 0) continue;
            Company c = new Company();
            c.setGroupId("demo");
            c.setType("IN");
            c.setName(name);
            c.setTelecom(String.valueOf(s[1]));
            c.setPhone(String.valueOf(s[2]));
            c.setFax(blankStr(String.valueOf(s[3])));
            c.setManagerName(String.valueOf(s[4]));
            c.setMobile(String.valueOf(s[5]));
            c.setBusinessName(String.valueOf(s[6]));
            c.setBusinessNumber(String.valueOf(s[7]));
            c.setActive(true);
            em.persist(c);
        }
    }

    private String blankStr(String v) { return v == null || v.isBlank() ? null : v; }

    private void seedOutcompaniesEnrich() {
        List<Company> outs = em.createQuery("select c from Company c where c.groupId='demo' and c.type in ('OUT','SHOP')", Company.class).getResultList();
        Object[][] extras = {
            {"대구 D1", "도매", "판매점", "P0001", "김영업", "010-1111-1001", "대구디원", "101-01-10001", "국민 111-111-111111"},
            {"경산 D2", "도매", "판매점", "P0002", "이영업", "010-1111-1002", "경산디투", "102-02-10002", "신한 222-222-222222"},
            {"대구 늘푸른통신", "도매", "판매점", "P0003", "박영업", "010-1111-1003", "늘푸른", "103-03-10003", "우리 333-333-333333"},
            {"스마트모바일", "소매", "판매점", "P0004", "최영업", "010-1111-1004", "스마트", "104-04-10004", "하나 444-444-444444"},
            {"블루폰", "특판", "판매점", "P0005", "정영업", "010-1111-1005", "블루폰", "105-05-10005", "농협 555-555-555555"},
            {"늘붉은통신", "도매", "판매점", "P1000", "홍길동", "010-1234-5678", "늘붉은통신", "106-06-10006", "국민은행 000-000-0000000 홍길동"},
            {"출고처 샘플", "기타", "출고처", "P2000", "이출고", "010-4444-5555", "출고샘플", "107-07-10007", null},
        };
        Map<String, Object[]> byName = new LinkedHashMap<>();
        for (Object[] s : extras) byName.put(String.valueOf(s[0]), s);
        for (Company c : outs) {
            Object[] s = byName.get(c.getName());
            if (s != null) {
                if (blankStr(c.getChannel()) == null) c.setChannel(String.valueOf(s[1]));
                if (blankStr(c.getCategory()) == null) c.setCategory(String.valueOf(s[2]));
                if (blankStr(c.getPcode()) == null) c.setPcode(String.valueOf(s[3]));
                if (blankStr(c.getSalesperson()) == null) c.setSalesperson(String.valueOf(s[4]));
                if (blankStr(c.getMobile()) == null) c.setMobile(String.valueOf(s[5]));
                if (blankStr(c.getBusinessName()) == null) c.setBusinessName(String.valueOf(s[6]));
                if (blankStr(c.getBusinessNumber()) == null) c.setBusinessNumber(String.valueOf(s[7]));
                if (blankStr(c.getBankAccount()) == null && s[8] != null) c.setBankAccount(String.valueOf(s[8]));
            } else {
                if (blankStr(c.getChannel()) == null) c.setChannel("도매");
                if (blankStr(c.getCategory()) == null) c.setCategory("SHOP".equals(c.getType()) ? "판매점" : "출고처");
                if (blankStr(c.getSalesperson()) == null) c.setSalesperson(c.getManagerName());
            }
        }
        // ensure sample names exist
        for (Object[] s : extras) {
            String name = String.valueOf(s[0]);
            boolean exists = outs.stream().anyMatch(c -> name.equals(c.getName()));
            if (exists) continue;
            Company c = new Company();
            c.setGroupId("demo");
            c.setType("OUT");
            c.setName(name);
            c.setChannel(String.valueOf(s[1]));
            c.setCategory(String.valueOf(s[2]));
            c.setPcode(String.valueOf(s[3]));
            c.setSalesperson(String.valueOf(s[4]));
            c.setManagerName(String.valueOf(s[4]));
            c.setPhone(String.valueOf(s[5]));
            c.setMobile(String.valueOf(s[5]));
            c.setBusinessName(String.valueOf(s[6]));
            c.setBusinessNumber(String.valueOf(s[7]));
            if (s[8] != null) c.setBankAccount(String.valueOf(s[8]));
            c.setActive(true);
            em.persist(c);
        }
    }

    private void seedDeliveriesIfEmpty() {
        Long count = em.createQuery("select count(c) from Company c where c.groupId='demo' and c.type='DELIVERY'", Long.class).getSingleResult();
        if (count != null && count >= 3) return;
        Object[][] samples = {
            {"대한통운", "1588-1255", null},
            {"오성퀵", "000-0000-0000", null},
            {"해운퀵", "000-0000-0000", null},
        };
        for (Object[] s : samples) {
            String name = String.valueOf(s[0]);
            Long exists = em.createQuery("select count(c) from Company c where c.groupId='demo' and c.type='DELIVERY' and c.name=:n", Long.class)
                .setParameter("n", name).getSingleResult();
            if (exists != null && exists > 0) continue;
            Company c = new Company();
            c.setGroupId("demo");
            c.setType("DELIVERY");
            c.setName(name);
            c.setPhone(String.valueOf(s[1]));
            c.setMemo(s[2] == null ? null : String.valueOf(s[2]));
            c.setActive(true);
            em.persist(c);
        }
    }

    private void seedPreferenceIfEmpty() {
        Long count = em.createQuery("select count(s) from Setting s where s.groupId='demo' and s.settingKey='preference'", Long.class).getSingleResult();
        if (count != null && count > 0) return;
        String json = "{"
            + "\"company\":{"
            + "\"name\":\"에이전트 데모\","
            + "\"managerName\":\"김대표\","
            + "\"mobile\":\"010-0000-0000\","
            + "\"businessName\":\"에이전트 데모\","
            + "\"businessNumber\":\"123-45-67890\","
            + "\"ceo\":\"김유신\","
            + "\"bizType\":\"도소매\","
            + "\"bizItem\":\"휴대폰판매\","
            + "\"address\":\"대구시 수성구 수성4가 먼길\""
            + "},"
            + "\"accessIps\":{\"enabled\":false,\"ips\":[]},"
            + "\"masking\":{\"enabled\":true,\"name\":true,\"phone\":true,\"rrn\":true,\"address\":false},"
            + "\"outCategories\":[\"판매점\",\"도매\"],"
            + "\"stock\":{\"duplicateSerialCheck\":true,\"allowNegative\":false,\"autoRecallDays\":0},"
            + "\"open\":{\"requireUsim\":true,\"requirePhone\":true,\"defaultOpenHow\":\"\",\"autoSettle\":false}"
            + "}";
        Setting s = new Setting();
        s.setGroupId("demo");
        s.setSettingKey("preference");
        s.setValue(json);
        em.persist(s);
    }

    private void seedCsNoticesIfEmpty() {
        Long count = em.createQuery("select count(b) from BbsPost b where b.groupId='demo' and b.code='cs'", Long.class).getSingleResult();
        if (count != null && count >= 20) return;
        Object[][] samples = {
            {"고객센터 5월 4일(월) 임시휴무안내", 6, LocalDate.of(2026, 4, 29)},
            {"지원금표기 관련 설정업데이트", 7, LocalDate.of(2025, 7, 30)},
            {"지원금표기 관련 설정업데이트 안내", 8, LocalDate.of(2025, 7, 30)},
            {"개통등록 화면 개선 안내", 12, LocalDate.of(2025, 7, 15)},
            {"문자발송 시스템 점검 안내", 18, LocalDate.of(2025, 6, 20)},
            {"요금수납 기능 업데이트 안내", 22, LocalDate.of(2025, 5, 28)},
            {"개인정보 마스킹 기능 추가 안내", 31, LocalDate.of(2025, 4, 10)},
            {"출고처 분류 설정 방법 안내", 15, LocalDate.of(2025, 3, 22)},
            {"재고관리 바코드 스캔 개선", 27, LocalDate.of(2025, 2, 14)},
            {"정산자료 엑셀다운로드 오류 수정", 19, LocalDate.of(2025, 1, 20)},
            {"연말연시 고객센터 운영안내", 45, LocalDate.of(2024, 12, 24)},
            {"에이전트샵 접속 장애 복구 안내", 38, LocalDate.of(2024, 11, 8)},
            {"보안 업데이트 적용 안내", 52, LocalDate.of(2024, 10, 15)},
            {"신규 통신사 요금제 등록 안내", 24, LocalDate.of(2024, 9, 3)},
            {"모바일 앱 버전 업데이트 안내", 41, LocalDate.of(2024, 8, 12)},
            {"스캔신청서 접수 문자 설정 안내", 16, LocalDate.of(2024, 7, 25)},
            {"서버 정기점검 안내 (7/20)", 33, LocalDate.of(2024, 7, 18)},
            {"개통내역 일괄삭제 기능 추가", 29, LocalDate.of(2024, 6, 5)},
            {"유심거래장부 메뉴 오픈 안내", 21, LocalDate.of(2024, 5, 17)},
            {"비밀번호 변경 권고 안내", 67, LocalDate.of(2024, 4, 2)},
            {"고객센터 설 연휴 휴무안내", 55, LocalDate.of(2024, 2, 8)},
            {"프로그램 이용약관 개정 안내", 48, LocalDate.of(2024, 1, 15)},
            {"엑셀 업로드 양식 변경 안내", 36, LocalDate.of(2023, 12, 1)},
            {"출고처 일괄등록 기능 추가", 28, LocalDate.of(2023, 10, 20)},
            {"알림톡 발송 서비스 오픈", 44, LocalDate.of(2023, 9, 8)},
            {"재고실사 기능 사용방법 안내", 39, LocalDate.of(2023, 8, 14)},
            {"로그인 2단계 인증 안내", 61, LocalDate.of(2023, 7, 3)},
            {"고객센터 추석 연휴 휴무안내", 50, LocalDate.of(2023, 9, 25)},
            {"개통수수료 정산 로직 변경", 34, LocalDate.of(2023, 6, 12)},
            {"브라우저 권장사양 안내", 72, LocalDate.of(2023, 5, 1)},
        };
        for (Object[] s : samples) {
            String title = String.valueOf(s[0]);
            Long exists = em.createQuery("select count(b) from BbsPost b where b.groupId='demo' and b.code='cs' and b.title=:t", Long.class)
                .setParameter("t", title).getSingleResult();
            if (exists != null && exists > 0) continue;
            BbsPost b = new BbsPost();
            b.setGroupId("demo");
            b.setCode("cs");
            b.setTitle(title);
            b.setContents("<p>" + title + "</p><p>자세한 내용은 고객센터(1600-3903)로 문의해 주세요.</p>");
            b.setAuthorName("비즈케어");
            b.setUserid("system");
            b.setTargetGroup("전체");
            b.setNotice(false);
            b.setViews((Integer) s[1]);
            b.setConfirmCount(0);
            b.setState("1");
            em.persist(b);
            em.flush();
            LocalDate d = (LocalDate) s[2];
            b.setCreatedAt(d.atStartOfDay(ZoneId.of("Asia/Seoul")).toInstant());
            b.setUpdatedAt(b.getCreatedAt());
        }
    }

    private void seedCsInquiriesIfEmpty() {
        Long count = em.createQuery("select count(c) from CsInquiry c where c.groupId='demo'", Long.class).getSingleResult();
        // ensure sample matching original screenshot exists
        Long test3 = em.createQuery("select count(c) from CsInquiry c where c.groupId='demo' and c.title='test3'", Long.class).getSingleResult();
        if (test3 == null || test3 == 0) {
            CsInquiry c = new CsInquiry();
            c.setGroupId("demo");
            c.setUserid("demo");
            c.setAuthorName("김대표");
            c.setTitle("test3");
            c.setContent("테스트 문의입니다.");
            c.setReply("확인되었습니다. 추가 문의사항이 있으시면 남겨주세요.");
            c.setStatus("답변완료");
            c.setReplyCount(1);
            em.persist(c);
            em.flush();
            c.setCreatedAt(LocalDate.of(2019, 11, 5).atStartOfDay(ZoneId.of("Asia/Seoul")).toInstant());
            c.setUpdatedAt(c.getCreatedAt());
        }
        if (count != null && count >= 1) {
            for (CsInquiry c : em.createQuery("select c from CsInquiry c where c.groupId='demo'", CsInquiry.class).getResultList()) {
                if (c.getAuthorName() == null || c.getAuthorName().isBlank()) c.setAuthorName("김대표");
                if (c.getStatus() == null || "OPEN".equalsIgnoreCase(c.getStatus())) c.setStatus("답변대기");
                if ("DONE".equalsIgnoreCase(c.getStatus())) c.setStatus("답변완료");
                if (c.getReplyCount() == null) c.setReplyCount(c.getReply() != null && !c.getReply().isBlank() ? 1 : 0);
            }
        }
    }

    private void seedInternalBoardIfEmpty() {
        Long count = em.createQuery("select count(b) from BbsPost b where b.groupId='demo' and b.code='company'", Long.class).getSingleResult();
        if (count != null && count >= 5) return;
        Object[][] samples = {
            {"7", "김대표", 0, LocalDate.of(2023, 6, 23), 0},
            {"업무공지", "김대표", 20, LocalDate.of(2021, 2, 15), 0},
            {"zcxvzxcv", "김대표", 6, LocalDate.of(2020, 11, 13), 0},
            {"124", "오영업", 14, LocalDate.of(2019, 8, 8), 1},
            {"124", "김대표", 8, LocalDate.of(2019, 8, 2), 0},
        };
        for (Object[] s : samples) {
            String title = String.valueOf(s[0]);
            String author = String.valueOf(s[1]);
            LocalDate date = (LocalDate) s[3];
            Long exists = em.createQuery(
                "select count(b) from BbsPost b where b.groupId='demo' and b.code='company' and b.title=:t and b.authorName=:a", Long.class)
                .setParameter("t", title).setParameter("a", author).getSingleResult();
            if (exists != null && exists > 0) {
                // still update date/views for matching sample
                continue;
            }
            BbsPost b = new BbsPost();
            b.setGroupId("demo");
            b.setCode("company");
            b.setTitle(title);
            b.setContents("<p>" + title + "</p>");
            b.setAuthorName(author);
            b.setUserid("demo");
            b.setTargetGroup("전체");
            b.setNotice(false);
            b.setViews((Integer) s[2]);
            b.setCommentCount((Integer) s[4]);
            b.setConfirmCount(0);
            b.setState("1");
            em.persist(b);
            em.flush();
            b.setCreatedAt(date.atStartOfDay(ZoneId.of("Asia/Seoul")).toInstant());
            b.setUpdatedAt(b.getCreatedAt());
        }
    }

    private void seedScheduleSampleIfEmpty() {
        LocalDate d = LocalDate.of(2026, 7, 11);
        Long exists = em.createQuery(
            "select count(s) from ScheduleItem s where s.groupId='demo' and s.sdate=:d and s.contents=:c", Long.class)
            .setParameter("d", d).setParameter("c", "ㅇㄴㅁㄹㅇㄴㅁ").getSingleResult();
        if (exists != null && exists > 0) return;
        ScheduleItem s = new ScheduleItem();
        s.setGroupId("demo");
        s.setUserid("demo");
        s.setSdate(d);
        s.setStime("01:30");
        s.setContents("ㅇㄴㅁㄹㅇㄴㅁ");
        em.persist(s);
    }

    private void seedPostitsIfEmpty() {
        String json = "["
            + "{\"slot\":1,\"title\":\"포스트잇 #1\",\"contents\":\"신규 예약 개통 오예\",\"authorName\":\"김대표\",\"noteDate\":\"26-06-08\"},"
            + "{\"slot\":2,\"title\":\"포스트잇 #2\",\"contents\":\"demo\",\"authorName\":\"김대표\",\"noteDate\":\"26-06-08\"},"
            + "{\"slot\":3,\"title\":\"포스트잇 #3\",\"contents\":\"유심 발주 요청\",\"authorName\":\"이과장\",\"noteDate\":\"26-06-05\"},"
            + "{\"slot\":4,\"title\":\"포스트잇 #4\",\"contents\":\"정산서 마감 체크\",\"authorName\":\"김대표\",\"noteDate\":\"26-05-28\"},"
            + "{\"slot\":5,\"title\":\"포스트잇 #5\",\"contents\":\"스캔자료 검토\",\"authorName\":\"오영업\",\"noteDate\":\"26-05-20\"},"
            + "{\"slot\":6,\"title\":\"포스트잇 #6\",\"contents\":\"정책단가 업데이트\",\"authorName\":\"정총괄\",\"noteDate\":\"26-05-12\"},"
            + "{\"slot\":7,\"title\":\"포스트잇 #7\",\"contents\":\"고객센터 휴무 안내\",\"authorName\":\"김대표\",\"noteDate\":\"26-04-29\"},"
            + "{\"slot\":8,\"title\":\"포스트잇 #8\",\"contents\":\"월간 리포트 작성\",\"authorName\":\"이과장\",\"noteDate\":\"26-04-15\"}"
            + "]";
        List<Setting> rows = em.createQuery("select s from Setting s where s.groupId='demo' and s.settingKey='postits'", Setting.class).getResultList();
        if (rows.isEmpty()) {
            Setting s = new Setting();
            s.setGroupId("demo");
            s.setSettingKey("postits");
            s.setValue(json);
            em.persist(s);
            return;
        }
        Setting existing = rows.get(0);
        if (existing.getValue() != null && existing.getValue().contains("재고실사")) {
            existing.setValue(json);
        }
    }

    private void seedOpenStatsDemo() {
        LocalDate today = LocalDate.now();
        LocalDate day8 = today.withDayOfMonth(Math.min(8, today.lengthOfMonth()));
        LocalDate day9 = today.withDayOfMonth(Math.min(9, today.lengthOfMonth()));
        List<Company> shops = em.createQuery("select c from Company c where c.groupId='demo' and c.type in ('SHOP','OUT') order by c.id", Company.class).getResultList();
        List<Company> ins = em.createQuery("select c from Company c where c.groupId='demo' and c.type='IN' order by c.id", Company.class).getResultList();
        if (shops.isEmpty()) return;
        Long inId = ins.isEmpty() ? null : ins.getFirst().getId();
        ensureOpenStatSample(day8, "기변", "20000", shops.getFirst().getId(), inId, "SM-S928N");
        ensureOpenStatSample(day9, "보상", "25000", shops.get(Math.min(1, shops.size() - 1)).getId(), inId, "SM-A175N");
        LocalDate apr = LocalDate.of(today.getYear(), 4, 12);
        LocalDate jul = LocalDate.of(today.getYear(), 7, Math.min(10, today.lengthOfMonth()));
        if (shops.size() > 2) ensureOpenStatSample(apr, "신규", "18000", shops.get(2).getId(), inId, "SM-F766NK");
        if (shops.size() > 3) ensureOpenStatSample(apr, "MNP", "22000", shops.get(3).getId(),
            ins.size() > 1 ? ins.get(1).getId() : inId, "SM-S942NK");
        ensureOpenStatSample(jul, "신규", "21000", shops.getFirst().getId(), inId, "SM-S942N_256G");
        if (shops.size() > 1) ensureOpenStatSample(jul, "기변", "19000", shops.get(1).getId(), inId, "SM-A175N");
    }

    private void ensureOpenStatSample(LocalDate date, String openhow, String margin, Long shopId, Long inId) {
        ensureOpenStatSample(date, openhow, margin, shopId, inId, "SM-S928N");
    }

    private void ensureOpenStatSample(LocalDate date, String openhow, String margin, Long shopId, Long inId, String model) {
        Long count = em.createQuery(
            "select count(o) from OpenRecord o where o.groupId='demo' and o.opendate=:d and o.openhow=:h and o.pmodel=:m", Long.class)
            .setParameter("d", date).setParameter("h", openhow).setParameter("m", model).getSingleResult();
        if (count != null && count > 0) return;
        OpenRecord open = new OpenRecord();
        open.setGroupId("demo");
        open.setOutcompanyId(shopId);
        open.setIncompanyId(inId);
        open.setGubun("할부");
        open.setTelecom("SKT");
        open.setOpenhow(openhow);
        open.setName("통계*샘플");
        open.setOpenphone("010-****-0000");
        open.setOpendate(date);
        open.setOpenHour(11);
        open.setOpenMinute(0);
        open.setOpenStatus("정상");
        open.setOutCategory("판매점");
        open.setSalesperson("김영업");
        open.setEmployee("demo");
        open.setPlan("5GX 프라임");
        open.setPmodel(model);
        open.setPserial("STAT" + date.getMonthValue() + date.getDayOfMonth() + model.hashCode());
        open.setSellprice(BigDecimal.ZERO);
        open.setDealermargin1(new BigDecimal(margin));
        open.setDealermargin2(BigDecimal.ZERO);
        open.setState("OPEN");
        open.setUserid("demo");
        open.setUid("open-stat-" + openhow + "-" + date + "-" + model);
        em.persist(open);
    }

    private void seedHomeIndocsIfEmpty() {
        Long count = em.createQuery("select count(d) from HomeIncompleteDoc d where d.groupId='demo'", Long.class).getSingleResult();
        if (count > 0) return;
        List<Company> shops = em.createQuery("select c from Company c where c.groupId='demo' and c.type in ('SHOP','OUT')", Company.class).getResultList();
        List<Company> ins = em.createQuery("select c from Company c where c.groupId='demo' and c.type='IN'", Company.class).getResultList();
        if (shops.isEmpty()) return;
        Long inId = ins.isEmpty() ? null : ins.getFirst().getId();
        Object[][] samples = {
            {"SKT", "김*근", "010-****-3566", "인터넷,TV", "신분증사본", "30000", "서류미비"},
            {"KT", "박*지", "010-****-1122", "인터넷", "통장사본", "20000", "추가서류"},
            {"LGU+", "이*수", "010-****-5678", "TV,집전화", "인감증명서", "50000", "대리신청"},
        };
        for (int i = 0; i < samples.length; i++) {
            Object[] s = samples[i];
            HomeIncompleteDoc d = new HomeIncompleteDoc();
            d.setGroupId("demo");
            d.setOutcompanyId(shops.get(i % shops.size()).getId());
            d.setIncompanyId(inId);
            d.setOutcompanyName(shops.get(i % shops.size()).getName());
            d.setTelecom(String.valueOf(s[0]));
            d.setCustomerName(String.valueOf(s[1]));
            d.setPhone(String.valueOf(s[2]));
            d.setProducts(String.valueOf(s[3]));
            d.setMissingDocs(String.valueOf(s[4]));
            d.setDeductAmount(new BigDecimal(String.valueOf(s[5])));
            d.setDeductReason(String.valueOf(s[6]));
            d.setInstallDate(LocalDate.now().minusDays(i * 2));
            d.setDeadline(LocalDate.now().plusDays(7 - i));
            d.setStatus("미비");
            em.persist(d);
        }
    }

    private void seedHomeSalesIfEmpty() {
        Long count = em.createQuery("select count(h) from HomeSale h where h.groupId='demo'", Long.class).getSingleResult();
        if (count > 0) return;
        List<Company> shops = em.createQuery("select c from Company c where c.groupId='demo' and c.type in ('SHOP','OUT')", Company.class).getResultList();
        List<Company> ins = em.createQuery("select c from Company c where c.groupId='demo' and c.type='IN'", Company.class).getResultList();
        if (shops.isEmpty()) return;
        Long inId = ins.isEmpty() ? null : ins.getFirst().getId();
        Object[][] samples = {
            {"완료", "SKT", "인터넷,TV", "김*근", "010-****-3566", "-700000", "50000", "D2"},
            {"대기", "KT", "인터넷", "박*지", "010-****-1122", "0", "30000", "늘푸른통신"},
            {"완료", "LGU+", "TV,집전화", "이*수", "010-****-5678", "-1000000", "80000", "스마트모바일"},
            {"완료", "SKT", "홈IOT,기타", "최*아", "010-****-7788", "-200000", "20000", "블루폰"},
            {"대기", "KT", "소호,원스톱", "정*호", "010-****-9900", "0", "15000", "메인텔레콤"},
            {"완료", "SKT", "인터넷전화,신용카드", "홍*동", "010-****-2222", "-350000", "40000", "늘붉은통신"},
            {"완료", "LGU+", "후결합,재약정", "윤*희", "010-****-3344", "-150000", "25000", "D1"},
            {"대기", "KT", "렌탈", "한*진", "010-****-4455", "0", "10000", "늘푸른통신"},
        };
        for (int i = 0; i < samples.length; i++) {
            Object[] s = samples[i];
            HomeSale h = new HomeSale();
            h.setGroupId("demo");
            h.setOutcompanyId(shops.get(i % shops.size()).getId());
            h.setIncompanyId(inId);
            h.setStatus(String.valueOf(s[0]));
            h.setTelecom(String.valueOf(s[1]));
            h.setProducts(String.valueOf(s[2]));
            h.setCustomerName(String.valueOf(s[3]));
            h.setPhone(String.valueOf(s[4]));
            h.setSettleAmount(new BigDecimal(String.valueOf(s[5])));
            h.setMargin(new BigDecimal(String.valueOf(s[6])));
            h.setOutcompanyName(String.valueOf(s[7]));
            h.setOutCategory("판매점");
            h.setEmployee("demo");
            h.setInstallDate(LocalDate.now().minusDays(i));
            h.setReceiptDate(LocalDate.now().minusDays(i + 1));
            h.setMissingDocs("관계없음");
            h.setExtraPolicy(BigDecimal.ZERO);
            h.setAddress("서울시 강남구");
            em.persist(h);
        }
    }

    private void seedCareHomesIfEmpty() {
        if (em.createQuery("select count(p) from HomesProduct p where p.groupId='demo'", Long.class).getSingleResult() == 0) {
            Object[][] products = {
                {"INTERNET", "인터넷", "KT", "안심 인터넷 베이직 와이드", null, 36, "80000", 3},
                {"INTERNET", "인터넷", "KT", "인터넷 슬림", null, 36, "50000", 1},
                {"INTERNET", "인터넷", "KT", "기가인터넷 500M", null, 36, "80000", 0},
                {"INTERNET", "인터넷", "KT", "기가인터넷 1G", null, 36, "90000", 2},
                {"INTERNET", "인터넷", "KT", "인터넷 베이직 와이파이", null, 36, "60000", 1},
                {"INTERNET", "인터넷", "KT", "인터넷 에센스", null, 36, "70000", 0},
                {"INTERNET", "인터넷", "KT", "인터넷 베이직", null, 36, "55000", 0},
                {"INTERNET", "인터넷", "KT", "인터넷 프리미엄", null, 36, "100000", 3},
                {"INTERNET", "인터넷", "SKB", "B tv 인터넷", null, 36, "75000", 1},
                {"INTERNET", "인터넷", "LGU+", "U+ 인터넷", null, 36, "70000", 0},
                {"INTERNET", "TV", "KT", "올레tv 베이직", null, 36, "30000", 1},
                {"INTERNET", "TV", "KT", "올레tv 슬림", null, 36, "25000", 0},
                {"INTERNET", "TV", "KT", "지니 TV 프리미엄", null, 36, "40000", 2},
                {"INTERNET", "전화", "KT", "집전화 기본", null, 24, "10000", 0},
                {"INTERNET", "전화", "KT", "집전화 스마트", null, 24, "15000", 1},
                {"INTERNET", "와이파이", "KT", "와이파이 공유기", null, 24, "15000", 0},
                {"INTERNET", "와이파이", "SKB", "와이파이 메시", null, 24, "20000", 1},
                {"INTERNET", "스마트홈", "LGU+", "스마트홈 패키지", null, 36, "20000", 0},
                {"INTERNET", "스마트홈", "KT", "GiGA IoT 홈캠", null, 36, "25000", 1},
                {"INTERNET", "기타", "KT", "기타 부가상품", null, 12, "5000", 0},
                {"HOME", "정수기", "청호나이스", "450 (냉온정)", "WP-40C9500M", 60, "120000", 1},
                {"HOME", "정수기", "청호나이스", "550 (얼음냉온정)", "WI-55S9500M", 60, "150000", 0},
                {"HOME", "정수기", "청호나이스", "Compact (정)", "WP-CP1000", 60, "90000", 0},
                {"HOME", "정수기", "청호나이스", "700 (얼음냉온정)", "WI-70S9500M", 60, "180000", 1},
                {"HOME", "정수기", "코웨이", "아이콘 정수기", "CHP-7210N", 60, "130000", 0},
                {"HOME", "정수기", "코웨이", "냉온정수기", "CHP-5610L", 36, "110000", 1},
                {"HOME", "정수기", "SK매직", "스스로살균 정수기", "WPU-A110C", 60, "100000", 0},
                {"HOME", "정수기", "LG전자", "퓨리케어 오브제", "WD503AS", 60, "140000", 0},
                {"HOME", "공기청정기", "LG전자", "퓨리케어 360", "AS180DWFA", 36, "90000", 0},
                {"HOME", "공기청정기", "코웨이", "에어메가", "AP-2021A", 36, "85000", 1},
                {"HOME", "공기청정기", "삼성", "비스포크 큐브", "AX60A", 36, "95000", 0},
                {"HOME", "비데", "SK매직", "비데 기본형", "BIDET-01", 36, "50000", 0},
                {"HOME", "비데", "코웨이", "스스로케어 비데", "BAU-20", 36, "60000", 1},
                {"HOME", "비데", "청호나이스", "방수비데", "BA-17", 0, "45000", 0},
                {"HOME", "매트리스", "코웨이", "매트리스 퀸", "MT-Q", 60, "150000", 0},
                {"HOME", "매트리스", "코웨이", "매트리스 킹", "MT-K", 60, "180000", 1},
                {"HOME", "매트리스", "시몬스", "뷰티레스트", "BR-Q", 0, "200000", 0},
                {"HOME", "가전", "삼성", "김치냉장고", "RQ33A74", 36, "80000", 0},
                {"HOME", "가전", "LG전자", "디오스 냉장고", "M872GBB", 36, "100000", 0},
                {"HOME", "가전", "위닉스", "제습기", "DXAE100-KEK", 24, "40000", 1},
                {"HOME", "기타", "기타", "렌탈 기타상품", "ETC-01", 12, "30000", 0},
            };
            for (Object[] s : products) {
                HomesProduct p = new HomesProduct();
                p.setGroupId("demo");
                p.setKind(String.valueOf(s[0]));
                p.setCategory(String.valueOf(s[1]));
                p.setCompany(String.valueOf(s[2]));
                p.setName(String.valueOf(s[3]));
                p.setModel(s[4] == null ? null : String.valueOf(s[4]));
                p.setMonths((Integer) s[5]);
                p.setPolicyAmount(new BigDecimal(String.valueOf(s[6])));
                p.setPolicyCount((Integer) s[7]);
                em.persist(p);
            }
        }
        if (em.createQuery("select count(c) from HomesCustomer c where c.groupId='demo'", Long.class).getSingleResult() == 0) {
            Object[][] customers = {
                {"단골", "개인", "임*무", "010-1111-3203", "010-2222-8715", "서울시 강남구", "김사원", LocalDate.of(2024, 4, 26)},
                {"단골", "개인", "홍*동", "010-3333-2222", "", "서울시 서초구", "홍길동", LocalDate.of(2024, 4, 26)},
                {"단골1", "개인", "박*지", "010-2222-1122", "010-9999-1122", "서울시 마포구", "홍길동", LocalDate.of(2024, 5, 10)},
                {"단골2", "사업자", "최*아", "010-4444-7788", "", "인천시 연수구", "김대표", LocalDate.of(2024, 6, 1)},
                {"단골3", "개인", "정*민", "010-5555-9900", "010-5555-1111", "부산시 해운대", "홍총괄", LocalDate.of(2024, 7, 15)},
                {"분류없음", "개인", "이*수", "010-3333-5678", "", "경기도 성남시", "김대표", LocalDate.of(2024, 8, 20)},
                {"단골4", "개인", "김*근", "010-1111-3566", "", "서울시 송파구", "김사원", LocalDate.of(2024, 9, 5)},
            };
            for (Object[] s : customers) {
                HomesCustomer c = new HomesCustomer();
                c.setGroupId("demo");
                c.setGrade(String.valueOf(s[0]));
                c.setCustomerType(String.valueOf(s[1]));
                c.setName(String.valueOf(s[2]));
                c.setPhone(String.valueOf(s[3]));
                c.setPhoneAlt(String.valueOf(s[4]));
                c.setAddress(String.valueOf(s[5]));
                c.setEmployee(String.valueOf(s[6]));
                c.setRegisteredDate((LocalDate) s[7]);
                em.persist(c);
            }
        } else {
            for (HomesCustomer c : em.createQuery("select c from HomesCustomer c where c.groupId='demo'", HomesCustomer.class).getResultList()) {
                if (c.getCustomerType() == null || c.getCustomerType().isBlank()) c.setCustomerType("개인");
                if ("일반".equals(c.getGrade())) c.setGrade("분류없음");
                if (c.getRegisteredDate() == null && c.getCreatedAt() != null) {
                    c.setRegisteredDate(c.getCreatedAt().atZone(ZoneId.systemDefault()).toLocalDate());
                }
                if (c.getRegisteredDate() == null) c.setRegisteredDate(LocalDate.now().minusDays(30));
            }
        }
        if (em.createQuery("select count(c) from HomesContract c where c.groupId='demo'", Long.class).getSingleResult() == 0) {
            Object[][] contracts = {
                {"INTERNET", "완료", "홍*동", "010-1111-1019", "광랜인터넷 와이파이, B tv All", "30150000", "28000000", "-940000", "SK브로드밴드", "홍길동"},
                {"INTERNET", "완료", "김*수", "010-2222-3344", "기가인터넷 500M", "80000", "70000", "10000", "늘푸른통신", "홍길동"},
                {"INTERNET", "완료", "이*아", "010-3333-5566", "올레tv 베이직, 집전화 기본", "40000", "35000", "5000", "(주)코웨이", "홍총괄"},
                {"INTERNET", "접수", "박*지", "010-2222-1122", "올레tv 베이직", "30000", "25000", "5000", "대박통신", "김대표"},
                {"INTERNET", "신청", "이*수", "010-3333-5678", "와이파이 공유기", "15000", "12000", "3000", "스마트홈", "홍길동"},
                {"INTERNET", "철회", "최*민", "010-7777-8899", "인터넷 슬림", "50000", "0", "0", "대박통신", "홍총괄"},
                {"INTERNET", "완료", "정*희", "010-8888-9900", "기가인터넷 1G", "90000", "80000", "10000", "늘푸른통신", "김대표"},
                {"HOME", "완료", "최*아", "010-4444-7788", "냉온정수기", "120000", "100000", "20000", "늘푸른통신", "김대표"},
                {"HOME", "접수", "정*민", "010-5555-9900", "공기청정기", "90000", "75000", "15000", "블루홈", "홍길동"},
                {"HOME", "철회", "윤*희", "010-6666-1122", "비데 기본형", "50000", "0", "0", "대박통신", "홍총괄"},
            };
            for (int i = 0; i < contracts.length; i++) {
                Object[] s = contracts[i];
                HomesContract c = new HomesContract();
                c.setGroupId("demo");
                c.setKind(String.valueOf(s[0]));
                c.setStatus(String.valueOf(s[1]));
                c.setCustomerType("개인");
                c.setCustomerName(String.valueOf(s[2]));
                c.setPhone(String.valueOf(s[3]));
                c.setProducts(String.valueOf(s[4]));
                c.setPolicySum(new BigDecimal(String.valueOf(s[5])));
                c.setSettleAmount(new BigDecimal(String.valueOf(s[6])));
                c.setMargin(new BigDecimal(String.valueOf(s[7])));
                c.setAgency(String.valueOf(s[8]));
                c.setEmployee(String.valueOf(s[9]));
                c.setPayMethod("자동이체");
                c.setContractDate(LocalDate.now().minusDays(i * 2L));
                c.setInstallDate("완료".equals(s[1]) ? LocalDate.now().minusDays(i) : null);
                c.setMonths(36);
                c.setAddress("서울시");
                c.setCustomerGrade("분류없음");
                c.setNationality("내국인");
                em.persist(c);
            }
        }
        if (em.createQuery("select count(b) from HomesBalance b where b.groupId='demo'", Long.class).getSingleResult() == 0) {
            Object[][] balances = {
                {"정산차감", "하부점", "늘푸른통신", "서류미비", "-21124", "서류 보완 요청"},
                {"정산추가", "직원", "김대표", "추가정책", "30000", null},
                {"정산차감", "직원", "김대표", "철회차감", "-10000", "철회 건"},
                {"정산추가", "하부점", "대박통신", "프로모션", "15000", null},
                {"정산차감", "하부점", "대박통신", "오등록", "-5000", null},
                {"정산추가", "직원", "홍길동", "인센티브", "20000", "월 인센티브"},
                {"정산차감", "직원", "홍길동", "과지급", "-8000", null},
            };
            for (int i = 0; i < balances.length; i++) {
                Object[] s = balances[i];
                HomesBalance b = new HomesBalance();
                b.setGroupId("demo");
                b.setBalanceType(String.valueOf(s[0]));
                b.setTargetType(String.valueOf(s[1]));
                b.setTargetName(String.valueOf(s[2]));
                b.setReason(String.valueOf(s[3]));
                b.setAmount(new BigDecimal(String.valueOf(s[4])));
                b.setMemo(s[5] == null ? null : String.valueOf(s[5]));
                b.setBaseDate(LocalDate.now().minusDays(i));
                if ("하부점".equals(b.getTargetType())) b.setAgency(b.getTargetName());
                else b.setCustomerName(b.getTargetName());
                em.persist(b);
            }
        } else {
            // 구 데이터(차감/추가) → 원본 라벨로 정규화 + 대상 필드 보강
            for (HomesBalance b : em.createQuery("select b from HomesBalance b where b.groupId='demo'", HomesBalance.class).getResultList()) {
                if ("차감".equals(b.getBalanceType())) b.setBalanceType("정산차감");
                if ("추가".equals(b.getBalanceType())) b.setBalanceType("정산추가");
                if (b.getTargetType() == null || b.getTargetType().isBlank()) {
                    if (b.getAgency() != null && !b.getAgency().isBlank()
                            && (b.getCustomerName() == null || b.getCustomerName().isBlank() || b.getCustomerName().contains("*"))) {
                        b.setTargetType("하부점");
                        b.setTargetName(b.getAgency());
                    } else {
                        b.setTargetType("직원");
                        b.setTargetName(b.getCustomerName() != null && !b.getCustomerName().isBlank() ? b.getCustomerName() : "김대표");
                    }
                }
                if ("정산차감".equals(b.getBalanceType()) && b.getAmount() != null && b.getAmount().signum() > 0) {
                    b.setAmount(b.getAmount().negate());
                }
            }
            long balCount = em.createQuery("select count(b) from HomesBalance b where b.groupId='demo'", Long.class).getSingleResult();
            if (balCount < 5) {
                Object[][] extra = {
                    {"정산차감", "하부점", "대박통신", "오등록", "-5000", null},
                    {"정산추가", "직원", "홍길동", "인센티브", "20000", "월 인센티브"},
                    {"정산차감", "직원", "홍길동", "과지급", "-8000", null},
                    {"정산추가", "하부점", "늘푸른통신", "프로모션", "15000", null},
                    {"정산차감", "직원", "김대표", "철회차감", "-10000", "철회 건"},
                };
                for (int i = 0; i < extra.length && balCount + i < 7; i++) {
                    Object[] s = extra[i];
                    HomesBalance b = new HomesBalance();
                    b.setGroupId("demo");
                    b.setBalanceType(String.valueOf(s[0]));
                    b.setTargetType(String.valueOf(s[1]));
                    b.setTargetName(String.valueOf(s[2]));
                    b.setReason(String.valueOf(s[3]));
                    b.setAmount(new BigDecimal(String.valueOf(s[4])));
                    b.setMemo(s[5] == null ? null : String.valueOf(s[5]));
                    b.setBaseDate(LocalDate.now().minusDays(i + 1));
                    if ("하부점".equals(b.getTargetType())) b.setAgency(b.getTargetName());
                    else b.setCustomerName(b.getTargetName());
                    em.persist(b);
                }
            }
        }
        if (em.createQuery("select count(i) from HomesInvoice i where i.groupId='demo'", Long.class).getSingleResult() == 0) {
            for (int i = 0; i < 6; i++) {
                YearMonth ym = YearMonth.now().minusMonths(i);
                HomesInvoice inv = new HomesInvoice();
                inv.setGroupId("demo");
                inv.setScope(i % 2 == 0 ? "PUBLISH" : "MY");
                inv.setYearMonth(ym.toString());
                inv.setEmployee("김대표");
                inv.setAgency("늘푸른통신");
                inv.setInternetCount(2 + i % 3);
                inv.setInternetAmount(new BigDecimal(50000 + i * 10000L));
                inv.setHomeCount(1 + i % 2);
                inv.setHomeAmount(new BigDecimal(80000 + i * 5000L));
                inv.setBalanceCount(i % 3);
                inv.setBalanceAmount(new BigDecimal(i % 2 == 0 ? -5000 : 10000));
                inv.setContractCount(inv.getInternetCount() + inv.getHomeCount());
                inv.setSettleAmount(inv.getInternetAmount().add(inv.getHomeAmount()).add(inv.getBalanceAmount()));
                inv.setAmount(inv.getSettleAmount());
                inv.setIssued(i != 0);
                inv.setStatus(i == 0 ? "대기" : "발행");
                inv.setConsent(i == 0 ? "-" : "대기");
                inv.setTaxInvoice(i == 0 ? "-" : "미발행");
                inv.setWithdrawStatus(i == 0 ? "-" : "대기");
                em.persist(inv);
            }
        } else {
            for (HomesInvoice inv : em.createQuery("select i from HomesInvoice i where i.groupId='demo'", HomesInvoice.class).getResultList()) {
                if (("발행".equals(inv.getStatus()) || "확정".equals(inv.getStatus())) && !Boolean.TRUE.equals(inv.getIssued())) {
                    inv.setIssued(true);
                }
                if (inv.getSettleAmount() == null && inv.getAmount() != null) inv.setSettleAmount(inv.getAmount());
                if (inv.getInternetCount() == null && inv.getAmount() != null) {
                    inv.setInternetCount(2);
                    inv.setInternetAmount(inv.getAmount().multiply(new BigDecimal("0.4")).setScale(0, java.math.RoundingMode.HALF_UP));
                    inv.setHomeCount(1);
                    inv.setHomeAmount(inv.getAmount().multiply(new BigDecimal("0.5")).setScale(0, java.math.RoundingMode.HALF_UP));
                    inv.setBalanceCount(1);
                    inv.setBalanceAmount(inv.getAmount().subtract(inv.getInternetAmount()).subtract(inv.getHomeAmount()));
                    inv.setContractCount(inv.getInternetCount() + inv.getHomeCount());
                }
            }
        }
        if (em.createQuery("select count(p) from HomesPending p where p.groupId='demo'", Long.class).getSingleResult() == 0) {
            Object[][] pendings = {
                {"접수", "일반", "설치 상담", "김*근", "010-1111-3566", "김대표", null, null, "14:00", 0, "방문 전 연락 요망"},
                {"접수", "약속1", "방문 약속", "박*지", "010-2222-1122", "홍길동", null, null, "10:30", 1, null},
                {"해결", "약속2", "계약 설명", "이*수", "010-3333-5678", "홍길동", "김대표", 2, "16:00", 2, "완료 확인"},
                {"접수", "일반", "회선 제한 상담", "제한설", "010-7777-8899", "김대표", null, null, "11:00", 6, null},
                {"해결", "약속1", "설치 일정 조율", "최*아", "010-4444-7788", "홍총괄", "홍총괄", 3, "15:30", 4, null},
                {"접수", "일반", "요금 안내", "정*민", "010-5555-9900", "홍길동", null, null, "09:00", 5, "오전 통화"},
                {"접수", "약속2", "해지 상담", "윤*희", "010-6666-1122", "김대표", null, null, "13:20", 7, null},
                {"해결", "일반", "AS 접수", "한*솔", "010-8888-3344", "홍길동", "홍길동", 1, "17:00", 8, null},
                {"접수", "약속1", "이전설치", "오*진", "010-9999-5566", "김대표", null, null, "12:00", 9, null},
                {"접수", "일반", "결합상품 문의", "배*수", "010-1212-3434", "홍총괄", null, null, "14:40", 10, null},
                {"해결", "약속2", "약정 연장", "임*영", "010-5656-7878", "홍길동", "김대표", 5, "10:00", 11, null},
                {"접수", "일반", "개통 일정", "조*현", "010-9090-1212", "김대표", null, null, "16:30", 12, null},
            };
            for (Object[] s : pendings) {
                HomesPending p = new HomesPending();
                p.setGroupId("demo");
                p.setStatus(String.valueOf(s[0]));
                p.setPendingType(String.valueOf(s[1]));
                p.setContents(String.valueOf(s[2]));
                p.setCustomerName(String.valueOf(s[3]));
                p.setPhone(String.valueOf(s[4]));
                p.setReceiveEmployee(String.valueOf(s[5]));
                p.setEmployee(String.valueOf(s[5]));
                p.setProcessEmployee(s[6] == null ? null : String.valueOf(s[6]));
                if (s[7] != null) p.setProcessDate(LocalDate.now().minusDays(((Number) s[7]).longValue()));
                p.setPendingTime(String.valueOf(s[8]));
                p.setPendingDate(LocalDate.now().plusDays(((Number) s[9]).longValue()));
                p.setMemo(s[10] == null ? null : String.valueOf(s[10]));
                em.persist(p);
            }
        } else {
            for (HomesPending p : em.createQuery("select p from HomesPending p where p.groupId='demo'", HomesPending.class).getResultList()) {
                if ("예정".equals(p.getStatus())) p.setStatus("접수");
                if ("완료".equals(p.getStatus())) p.setStatus("해결");
                if ((p.getReceiveEmployee() == null || p.getReceiveEmployee().isBlank()) && p.getEmployee() != null) {
                    p.setReceiveEmployee(p.getEmployee());
                }
            }
            long cnt = em.createQuery("select count(p) from HomesPending p where p.groupId='demo'", Long.class).getSingleResult();
            if (cnt < 8) {
                Object[][] extra = {
                    {"접수", "일반", "요금 안내", "정*민", "010-5555-9900", "홍길동", 5},
                    {"해결", "약속1", "설치 일정 조율", "최*아", "010-4444-7788", "홍총괄", 4},
                    {"접수", "약속2", "해지 상담", "윤*희", "010-6666-1122", "김대표", 7},
                    {"해결", "일반", "AS 접수", "한*솔", "010-8888-3344", "홍길동", 8},
                    {"접수", "약속1", "이전설치", "오*진", "010-9999-5566", "김대표", 9},
                    {"접수", "일반", "결합상품 문의", "배*수", "010-1212-3434", "홍총괄", 10},
                    {"해결", "약속2", "약정 연장", "임*영", "010-5656-7878", "홍길동", 11},
                    {"접수", "일반", "개통 일정", "조*현", "010-9090-1212", "김대표", 12},
                };
                for (int i = 0; i < extra.length && cnt + i < 12; i++) {
                    Object[] s = extra[i];
                    HomesPending p = new HomesPending();
                    p.setGroupId("demo");
                    p.setStatus(String.valueOf(s[0]));
                    p.setPendingType(String.valueOf(s[1]));
                    p.setContents(String.valueOf(s[2]));
                    p.setCustomerName(String.valueOf(s[3]));
                    p.setPhone(String.valueOf(s[4]));
                    p.setReceiveEmployee(String.valueOf(s[5]));
                    p.setEmployee(String.valueOf(s[5]));
                    if ("해결".equals(p.getStatus())) {
                        p.setProcessEmployee(String.valueOf(s[5]));
                        p.setProcessDate(LocalDate.now().minusDays(1));
                    }
                    p.setPendingTime("10:00");
                    p.setPendingDate(LocalDate.now().plusDays(((Number) s[6]).longValue()));
                    em.persist(p);
                }
            }
        }
        if (em.createQuery("select count(b) from HomesBooking b where b.groupId='demo'", Long.class).getSingleResult() == 0) {
            Object[][] bookings = {
                {"완료", "이*신", "0000-0000-0000", "인터넷, TV, 전화", "매트리스, 가전", LocalDate.of(2022, 7, 14)},
                {"접수", "홍*동", "010-1111-2222", "인터넷, 전화, 스마트홈", "공기청정기, 매트리스, 기타", LocalDate.of(2022, 7, 14)},
                {"보류", "김*근", "010-1000-2000", "인터넷, 와이파이", "정수기", LocalDate.now().plusDays(1)},
            };
            for (Object[] s : bookings) {
                HomesBooking b = new HomesBooking();
                b.setGroupId("demo");
                b.setStatus(String.valueOf(s[0]));
                b.setCustomerName(String.valueOf(s[1]));
                b.setPhone(String.valueOf(s[2]));
                b.setInternetProducts(String.valueOf(s[3]));
                b.setRentalProducts(String.valueOf(s[4]));
                b.setProducts(s[3] + ", " + s[4]);
                b.setBookingDate((LocalDate) s[5]);
                b.setAddress("서울시");
                b.setEmployee("홍길동");
                em.persist(b);
            }
        } else {
            // 기존 시드에 인터넷/홈렌탈 분리 필드 보강
            List<HomesBooking> existing = em.createQuery(
                    "select b from HomesBooking b where b.groupId='demo'", HomesBooking.class).getResultList();
            for (HomesBooking b : existing) {
                if (b.getInternetProducts() == null || b.getInternetProducts().isBlank()) {
                    String p = b.getProducts() == null ? "" : b.getProducts();
                    if (p.contains("인터넷") || p.contains("기가") || p.contains("TV") || p.contains("전화") || p.contains("와이파이") || p.contains("스마트")) {
                        List<String> inet = new ArrayList<>();
                        if (p.contains("인터넷") || p.contains("기가")) inet.add("인터넷");
                        if (p.contains("TV")) inet.add("TV");
                        if (p.contains("전화")) inet.add("전화");
                        if (p.contains("와이파이")) inet.add("와이파이");
                        if (p.contains("스마트")) inet.add("스마트홈");
                        if (inet.isEmpty()) inet.add("인터넷");
                        b.setInternetProducts(String.join(", ", inet));
                    }
                    if (p.contains("정수기") || p.contains("공기") || p.contains("비데") || p.contains("매트") || p.contains("가전")) {
                        List<String> rent = new ArrayList<>();
                        if (p.contains("정수기")) rent.add("정수기");
                        if (p.contains("공기")) rent.add("공기청정기");
                        if (p.contains("비데")) rent.add("비데");
                        if (p.contains("매트")) rent.add("매트리스");
                        if (p.contains("가전")) rent.add("가전");
                        b.setRentalProducts(String.join(", ", rent));
                    }
                    if ((b.getInternetProducts() == null || b.getInternetProducts().isBlank())
                            && (b.getRentalProducts() == null || b.getRentalProducts().isBlank())) {
                        b.setInternetProducts("인터넷");
                        b.setRentalProducts("기타");
                    }
                }
                if (b.getEmployee() == null || b.getEmployee().isBlank()) b.setEmployee("홍길동");
            }
        }
        if (em.createQuery("select count(a) from HomesAbook a where a.groupId='demo'", Long.class).getSingleResult() == 0) {
            Object[][] abooks = {
                {"입금", "일반", "계약정산", "150000", "홍길동"},
                {"출금", "일반", "사무용품", "35000", "홍길동"},
                {"입금", "123", "후정산추가", "10000", "홍길동"},
                {"카드입금", "일반", "카드매출", "55000", "김대표"},
                {"카드출금", "123", "카드수수료", "2200", "홍길동"},
                {"출금", "일반", "테스트2", "5000", "홍길동"},
            };
            for (int i = 0; i < abooks.length; i++) {
                Object[] s = abooks[i];
                HomesAbook a = new HomesAbook();
                a.setGroupId("demo");
                a.setEntryType(String.valueOf(s[0]));
                a.setCategory(String.valueOf(s[1]));
                a.setItem(String.valueOf(s[2]));
                a.setAmount(new BigDecimal(String.valueOf(s[3])));
                a.setEmployee(String.valueOf(s[4]));
                a.setEntryDate(LocalDate.now().minusDays(i));
                a.setMemo(i == 0 ? "데모 시드" : null);
                em.persist(a);
            }
        } else {
            for (HomesAbook a : em.createQuery("select a from HomesAbook a where a.groupId='demo'", HomesAbook.class).getResultList()) {
                if ("수입".equals(a.getEntryType())) a.setEntryType("입금");
                else if ("지출".equals(a.getEntryType())) a.setEntryType("출금");
                String cat = a.getCategory();
                boolean knownCat = cat != null && (cat.equals("일반") || cat.equals("123") || cat.startsWith("단골"));
                if (!knownCat && cat != null && !cat.isBlank()) {
                    if (a.getItem() == null || a.getItem().isBlank()) a.setItem(cat);
                    a.setCategory("일반");
                }
                if ((a.getItem() == null || a.getItem().isBlank()) && a.getAgency() != null && !a.getAgency().isBlank()) {
                    a.setItem(a.getAgency());
                }
                if (a.getCategory() == null || a.getCategory().isBlank()) a.setCategory("일반");
                if (a.getEmployee() == null || a.getEmployee().isBlank()) a.setEmployee("홍길동");
            }
        }
        {
            Object[][] agencies = {
                {"(주)코웨이", "", "", "", "", LocalDate.of(2022, 5, 27), true, null},
                {"SK브로드밴드", "", "", "", "", LocalDate.of(2022, 5, 27), true, null},
                {"테스트", "02-1234-5678", "02-9876-5432", "홍길동", "010-1234-5678", LocalDate.of(2022, 4, 13), true, "데모 거래처"},
            };
            java.util.Set<String> keep = new java.util.HashSet<>();
            for (Object[] s : agencies) keep.add(String.valueOf(s[0]));
            for (HomesAgency old : em.createQuery("select a from HomesAgency a where a.groupId='demo'", HomesAgency.class).getResultList()) {
                if (!keep.contains(old.getName())) em.remove(old);
            }
            em.flush();
            for (Object[] s : agencies) {
                String name = String.valueOf(s[0]);
                List<HomesAgency> found = em.createQuery(
                                "select a from HomesAgency a where a.groupId='demo' and a.name=:name", HomesAgency.class)
                        .setParameter("name", name).getResultList();
                HomesAgency a = found.isEmpty() ? new HomesAgency() : found.getFirst();
                a.setGroupId("demo");
                a.setName(name);
                a.setPhone(String.valueOf(s[1]));
                a.setFax(String.valueOf(s[2]));
                a.setManagerName(String.valueOf(s[3]));
                a.setMobile(String.valueOf(s[4]));
                a.setRegisteredDate((LocalDate) s[5]);
                a.setActive((Boolean) s[6]);
                a.setAgencyType("대리점");
                a.setAddress(null);
                a.setMemo(s[7] == null ? null : String.valueOf(s[7]));
                if (found.isEmpty()) em.persist(a);
            }
        }
        // 상부점/하부점관리 원본은 빈 목록
        for (HomesPartner p : em.createQuery("select p from HomesPartner p where p.groupId='demo'", HomesPartner.class).getResultList()) {
            em.remove(p);
        }
        em.flush();
        {
            // 공지사항 원본 샘플 1건
            String title = "비즈케어 홈즈를 베타오픈 하였습니다.";
            List<HomesNotice> all = em.createQuery("select n from HomesNotice n where n.groupId='demo'", HomesNotice.class).getResultList();
            HomesNotice target = all.stream().filter(n -> title.equals(n.getTitle())).findFirst().orElse(null);
            if (target == null) {
                for (HomesNotice old : all) em.remove(old);
                em.flush();
                target = new HomesNotice();
                target.setGroupId("demo");
                target.setTitle(title);
                target.setAuthorName("비즈케어");
                target.setContents("비즈케어 홈즈를 베타오픈 하였습니다.\n\n이용에 참고 부탁드립니다.");
                target.setViews(10);
                em.persist(target);
                em.flush();
            } else {
                target.setViews(target.getViews() == null || target.getViews() < 10 ? 10 : target.getViews());
                if (target.getContents() == null || target.getContents().isBlank()) {
                    target.setContents("비즈케어 홈즈를 베타오픈 하였습니다.\n\n이용에 참고 부탁드립니다.");
                }
            }
            Instant at = LocalDate.of(2022, 11, 22).atStartOfDay(ZoneId.of("Asia/Seoul")).toInstant();
            target.setCreatedAt(at);
            target.setUpdatedAt(at);
            // 원본과 다른 데모 공지 제거
            for (HomesNotice n : em.createQuery("select n from HomesNotice n where n.groupId='demo'", HomesNotice.class).getResultList()) {
                if (!title.equals(n.getTitle())) em.remove(n);
            }
        }
        // 사용문의 원본은 빈 목록
        for (HomesQuestion q : em.createQuery("select q from HomesQuestion q where q.groupId='demo'", HomesQuestion.class).getResultList()) {
            em.remove(q);
        }
        em.flush();
        // 사내게시판 원본은 빈 목록
        for (HomesBbs b : em.createQuery("select b from HomesBbs b where b.groupId='demo'", HomesBbs.class).getResultList()) {
            em.remove(b);
        }
        em.flush();
        if (em.createQuery("select count(r) from HomesReception r where r.groupId='demo'", Long.class).getSingleResult() == 0) {
            Object[][] rows = {
                {LocalDateTime.of(2026, 7, 10, 9, 12), "김상담", "강남점", "KT", "상품권", "인터넷", "기가인터넷 1G", "홍*동", "010-1111-2222", "서울", "1.접수완료", "SAMPLE-00001", "서울입고", "박처리", "접수", "현금", "100000", "정산대기", null, null, "미지급", "본사", "36개월", "02-1234-5678"},
                {LocalDateTime.of(2026, 7, 10, 10, 30), "이상담", "서초점", "SKB", "가전", "TV", "B tv 프리미엄", "김*수", "010-2222-3333", "경기", "2.고객통화", "SAMPLE-00002", "", "최처리", "통화완료", "계좌", "80000", "정산대기", null, null, "지급대기", "영업점", "24개월", ""},
                {LocalDateTime.of(2026, 7, 9, 14, 5), "김상담", "강남점", "LGU+", "상품권", "인터넷", "U+ 인터넷", "박*지", "010-3333-4444", "인천", "4.개통완료", "SAMPLE-00003", "서울입고", "박처리", "개통", "현금", "120000", "정산대기", LocalDate.of(2026, 7, 9), null, "미지급", "본사", "36개월", "032-555-1212"},
                {LocalDateTime.of(2026, 7, 8, 11, 20), "정상담", "송파점", "KT", "캐시백", "정수기", "청호 450", "최*아", "010-4444-5555", "서울", "4.개통완료", "SAMPLE-00004", "물류완료", "이처리", "설치완료", "카드", "150000", "정산완료", LocalDate.of(2026, 7, 8), LocalDate.of(2026, 7, 10), "지급완료", "본사", "60개월", ""},
                {LocalDateTime.of(2026, 7, 8, 16, 40), "이상담", "서초점", "SKT", "상품권", "전화", "집전화 스마트", "정*민", "010-5555-6666", "부산", "3.서류검토", "SAMPLE-00005", "", "최처리", "서류요청", "현금", "15000", "정산대기", null, null, "미지급", "본사", "24개월", ""},
                {LocalDateTime.of(2026, 7, 7, 9, 50), "김상담", "강남점", "KT", "가전", "공기청정기", "퓨리케어 360", "이*수", "010-6666-7777", "서울", "5.사은품지급", "SAMPLE-00006", "서울입고", "박처리", "사은품발송", "계좌", "90000", "정산대기", LocalDate.of(2026, 7, 6), LocalDate.of(2026, 7, 7), "지급완료", "본사", "36개월", ""},
                {LocalDateTime.of(2026, 7, 6, 13, 15), "정상담", "송파점", "SKB", "상품권", "인터넷", "B tv 인터넷", "윤*희", "010-7777-8888", "경기", "6.정산완료", "SAMPLE-00007", "완료", "이처리", "정산", "현금", "75000", "정산완료", LocalDate.of(2026, 7, 5), LocalDate.of(2026, 7, 6), "지급완료", "영업점", "36개월", ""},
                {LocalDateTime.of(2026, 7, 5, 15, 0), "이상담", "서초점", "LGU+", "캐시백", "와이파이", "와이파이 메시", "한*진", "010-8888-9999", "대전", "9.취소", "SAMPLE-00008", "", "최처리", "고객취소", "", "0", "회수대기", null, null, "반송", "", "12개월", ""},
                {LocalDateTime.of(2026, 7, 11, 8, 45), "김상담", "강남점", "KT", "상품권", "인터넷", "안심 인터넷 베이직", "오*라", "010-1212-3434", "서울", "1.접수완료", "SAMPLE-00009", "", "박처리", "접수", "현금", "60000", "정산대기", null, null, "미지급", "본사", "36개월", ""},
                {LocalDateTime.of(2026, 7, 11, 11, 10), "정상담", "송파점", "SKB", "가전", "비데", "스스로케어 비데", "서*호", "010-5656-7878", "경남", "2.고객통화", "SAMPLE-00010", "물류대기", "이처리", "통화예약", "계좌", "60000", "정산대기", null, null, "지급대기", "본사", "36개월", ""},
            };
            for (Object[] s : rows) {
                HomesReception r = new HomesReception();
                r.setGroupId("demo");
                r.setOrderDate((LocalDateTime) s[0]);
                r.setCounselor(String.valueOf(s[1]));
                r.setBranch(String.valueOf(s[2]));
                r.setCarrier(String.valueOf(s[3]));
                r.setGiftCategory(String.valueOf(s[4]));
                r.setProductCategory(String.valueOf(s[5]));
                r.setProductName(String.valueOf(s[6]));
                r.setCustomerName(String.valueOf(s[7]));
                r.setPhone(String.valueOf(s[8]));
                r.setRegion(String.valueOf(s[9]));
                r.setProgressStatus(String.valueOf(s[10]));
                r.setOrderNumber(String.valueOf(s[11]));
                r.setInboundInfo(String.valueOf(s[12]));
                r.setProcessor(String.valueOf(s[13]));
                r.setDetailProgress(String.valueOf(s[14]));
                r.setPaymentType(String.valueOf(s[15]));
                r.setAmount(new BigDecimal(String.valueOf(s[16])));
                r.setSettleStatus(String.valueOf(s[17]));
                r.setOpenDate(s[18] == null ? null : (LocalDate) s[18]);
                r.setGiftDate(s[19] == null ? null : (LocalDate) s[19]);
                r.setGiftStatus(String.valueOf(s[20]));
                r.setGiftPlace(String.valueOf(s[21]));
                r.setAgreementName(String.valueOf(s[22]));
                r.setContractNumber(String.valueOf(s[23]));
                r.setBranchGroup("본사그룹");
                r.setPostIt("");
                r.setMemo("데모 접수 데이터");
                em.persist(r);
            }
            em.flush();
            for (HomesReception r : em.createQuery("select r from HomesReception r where r.groupId='demo'", HomesReception.class).getResultList()) {
                HomesReceptionProgressLog log = new HomesReceptionProgressLog();
                log.setGroupId("demo");
                log.setReceptionId(r.getId());
                log.setStatus(r.getProgressStatus());
                log.setMemo("초기 등록");
                log.setAuthorName(r.getCounselor());
                log.setLoggedAt(r.getOrderDate() == null ? LocalDateTime.now() : r.getOrderDate());
                em.persist(log);
            }
        }
        seedReceptionIspsIfEmpty();
        enrichReceptionProgressFields();
        if (em.createQuery("select count(l) from HomesLog l where l.groupId='demo'", Long.class).getSingleResult() == 0) {
            Object[][] logs = {
                {"PRODUCT", "인터넷상품-등록", "인터넷상품 [센트릭스] 등록하였습니다.", "홍길동", 2},
                {"PRODUCT", "인터넷상품-정책-등록", "인터넷상품 정책 [36개월] 등록하였습니다.", "홍길동", 3},
                {"PRODUCT", "인터넷상품-수정", "인터넷상품 [기가인터넷 500M] 수정하였습니다.", "홍총괄", 5},
                {"PRODUCT", "홈렌탈상품-등록", "홈렌탈상품 [450 (냉온정)] 등록하였습니다.", "홍길동", 8},
                {"PRODUCT", "홈렌탈상품-정책-등록", "홈렌탈상품 정책 [60개월] 등록하였습니다.", "홍총괄", 10},
                {"PRODUCT", "인터넷상품-삭제", "인터넷상품 [인터넷 슬림] 삭제하였습니다.", "김대표", 12},
                {"PRODUCT", "기본상품-동기화", "인터넷상품 기본상품 16건을 동기화하였습니다.", "김대표", 20},
                {"CONTRACT", "인터넷접수-등록", "인터넷접수 [홍*동] 등록하였습니다.", "홍길동", 1},
                {"CONTRACT", "인터넷접수-상태", "인터넷접수 [홍*동] 완료(으)로 변경하였습니다.", "홍길동", 2},
                {"CONTRACT", "인터넷접수-수정", "인터넷접수 [김*수] 수정하였습니다.", "홍총괄", 4},
                {"CONTRACT", "홈렌탈접수-등록", "홈렌탈접수 [최*아] 등록하였습니다.", "김대표", 6},
                {"CONTRACT", "홈렌탈접수-상태", "홈렌탈접수 [윤*희] 철회(으)로 변경하였습니다.", "홍총괄", 9},
                {"CUSTOMER", "고객-등록", "고객 [위*우] 등록하였습니다.", "홍길동", 1},
                {"CUSTOMER", "고객-수정", "고객 [홍*동] 수정하였습니다.", "홍길동", 2},
                {"CUSTOMER", "고객-분류", "고객 [홍*동] 분류수정하였습니다.", "홍길동", 3},
                {"CUSTOMER", "고객-등록", "계약고객 [홍*동] 하부점(인터넷)에서 등록하였습니다.", "홍길동", 4},
                {"CUSTOMER", "고객-등록", "고객 [김*근] 등록하였습니다.", "김대표", 5},
                {"CUSTOMER", "고객-삭제", "고객 [이*수] 삭제하였습니다.", "홍길동", 8},
                {"BOOKING", "예약-상태", "예약 [이*신] 완료(으)로 상태변경하였습니다.", "홍길동", 1},
                {"BOOKING", "예약-수정", "예약 [홍*동] 수정하였습니다.", "홍길동", 2},
                {"BOOKING", "예약-등록", "예약 [이*신] 등록하였습니다.", "홍길동", 3},
                {"BOOKING", "예약-등록", "예약 [홍*동] 등록하였습니다.", "홍길동", 4},
                {"BOOKING", "예약-상태", "예약 [김*근] 보류(으)로 상태변경하였습니다.", "홍길동", 7},
                {"ABOOKS", "간편장부-등록", "간편장부 [입금/일반] 등록하였습니다.", "홍길동", 1},
                {"ABOOKS", "간편장부-수정", "간편장부 [출금/일반] 수정하였습니다.", "홍길동", 2},
                {"ABOOKS", "간편장부-삭제", "간편장부 [카드출금/123] 삭제하였습니다.", "홍길동", 3},
                {"ABOOKS", "간편장부-등록", "간편장부 [카드입금/일반] 등록하였습니다.", "김대표", 5},
                {"ABOOKS", "간편장부-등록", "간편장부 [출금/123] 등록하였습니다.", "홍길동", 8},
                {"INVOICE", "정산서-발행", "정산서 [김사원] 발행하였습니다.", "홍길동", 1},
                {"INVOICE", "정산서-발행", "정산서 [김대표] 발행하였습니다.", "김대표", 3},
                {"INVOICE", "정산서-재발행", "정산서 [홍길동] 재발행하였습니다.", "홍총괄", 5},
                {"INVOICE", "정산서-삭제", "정산서 [이총괄] 삭제하였습니다.", "김대표", 8},
                {"INVOICE", "정산서-발행", "정산서 [박재고] 발행하였습니다.", "홍길동", 12},
                {"INVOICE", "정산서-수정", "정산서 [김대표] 수정하였습니다.", "김대표", 15},
                {"INVOICE", "정산서-삭제", "정산서 [윤영업] 삭제하였습니다.", "홍길동", 20},
            };
            for (Object[] s : logs) {
                HomesLog l = new HomesLog();
                l.setGroupId("demo");
                l.setDomain(String.valueOf(s[0]));
                l.setAction(String.valueOf(s[1]));
                l.setContent(String.valueOf(s[2]));
                l.setStaff(String.valueOf(s[3]));
                l.setProcessedAt(LocalDateTime.now().minusHours(((Number) s[4]).longValue()));
                em.persist(l);
            }
        } else {
            // 정산서이력 데모 보강
            long invoiceLogs = em.createQuery("select count(l) from HomesLog l where l.groupId='demo' and l.domain='INVOICE'", Long.class).getSingleResult();
            if (invoiceLogs < 5) {
                Object[][] extra = {
                    {"정산서-발행", "정산서 [김사원] 발행하였습니다.", "홍길동", 2},
                    {"정산서-발행", "정산서 [김대표] 발행하였습니다.", "김대표", 6},
                    {"정산서-재발행", "정산서 [홍길동] 재발행하였습니다.", "홍총괄", 10},
                    {"정산서-삭제", "정산서 [이총괄] 삭제하였습니다.", "김대표", 14},
                    {"정산서-발행", "정산서 [박재고] 발행하였습니다.", "홍길동", 18},
                    {"정산서-수정", "정산서 [김대표] 수정하였습니다.", "김대표", 22},
                    {"정산서-삭제", "정산서 [윤영업] 삭제하였습니다.", "홍길동", 28},
                };
                for (Object[] s : extra) {
                    HomesLog l = new HomesLog();
                    l.setGroupId("demo");
                    l.setDomain("INVOICE");
                    l.setAction(String.valueOf(s[0]));
                    l.setContent(String.valueOf(s[1]));
                    l.setStaff(String.valueOf(s[2]));
                    l.setProcessedAt(LocalDateTime.now().minusHours(((Number) s[3]).longValue()));
                    em.persist(l);
                }
            }
            // 구 라벨 정규화
            for (HomesLog l : em.createQuery("select l from HomesLog l where l.groupId='demo' and l.domain='INVOICE'", HomesLog.class).getResultList()) {
                if ("발행".equals(l.getAction())) {
                    l.setAction("정산서-발행");
                    if (l.getContent() != null && !l.getContent().contains("정산서 [")) {
                        l.setContent("정산서 [" + l.getContent().replace(" 정산서를 발행하였습니다.", "").trim() + "] 발행하였습니다.");
                    }
                } else if ("등록".equals(l.getAction())) {
                    l.setAction("정산서-등록");
                    if (l.getContent() != null && !l.getContent().startsWith("정산서 [")) {
                        String[] parts = l.getContent().split(" ", 2);
                        String emp = parts.length > 1 ? parts[1] : parts[0];
                        l.setContent("정산서 [" + emp + "] 등록하였습니다.");
                    }
                } else if ("삭제".equals(l.getAction())) {
                    l.setAction("정산서-삭제");
                }
            }
            // 예약이력 데모 보강
            long bookingLogs = em.createQuery("select count(l) from HomesLog l where l.groupId='demo' and l.domain='BOOKING'", Long.class).getSingleResult();
            if (bookingLogs < 5) {
                Object[][] extra = {
                    {"예약-상태", "예약 [이*신] 완료(으)로 상태변경하였습니다.", "홍길동", 1},
                    {"예약-수정", "예약 [홍*동] 수정하였습니다.", "홍길동", 2},
                    {"예약-등록", "예약 [이*신] 등록하였습니다.", "홍길동", 3},
                    {"예약-등록", "예약 [홍*동] 등록하였습니다.", "홍길동", 4},
                    {"예약-상태", "예약 [김*근] 보류(으)로 상태변경하였습니다.", "홍길동", 7},
                };
                for (Object[] s : extra) {
                    HomesLog l = new HomesLog();
                    l.setGroupId("demo");
                    l.setDomain("BOOKING");
                    l.setAction(String.valueOf(s[0]));
                    l.setContent(String.valueOf(s[1]));
                    l.setStaff(String.valueOf(s[2]));
                    l.setProcessedAt(LocalDateTime.now().minusHours(((Number) s[3]).longValue()));
                    em.persist(l);
                }
            }
            for (HomesLog l : em.createQuery("select l from HomesLog l where l.groupId='demo' and l.domain='BOOKING'", HomesLog.class).getResultList()) {
                if ("등록".equals(l.getAction())) {
                    l.setAction("예약-등록");
                    if (l.getContent() != null && !l.getContent().startsWith("예약 [")) {
                        l.setContent("예약 [" + l.getContent().trim() + "] 등록하였습니다.");
                    }
                } else if ("수정".equals(l.getAction())) {
                    l.setAction("예약-수정");
                } else if ("삭제".equals(l.getAction())) {
                    l.setAction("예약-삭제");
                } else if ("상태".equals(l.getAction())) {
                    l.setAction("예약-상태");
                }
            }
            // 고객이력 데모 보강
            long customerLogs = em.createQuery("select count(l) from HomesLog l where l.groupId='demo' and l.domain='CUSTOMER'", Long.class).getSingleResult();
            if (customerLogs < 5) {
                Object[][] extra = {
                    {"고객-등록", "고객 [위*우] 등록하였습니다.", "홍길동", 1},
                    {"고객-수정", "고객 [홍*동] 수정하였습니다.", "홍길동", 2},
                    {"고객-분류", "고객 [홍*동] 분류수정하였습니다.", "홍길동", 3},
                    {"고객-등록", "계약고객 [홍*동] 하부점(인터넷)에서 등록하였습니다.", "홍길동", 4},
                    {"고객-등록", "고객 [김*근] 등록하였습니다.", "김대표", 5},
                    {"고객-삭제", "고객 [이*수] 삭제하였습니다.", "홍길동", 8},
                };
                for (Object[] s : extra) {
                    HomesLog l = new HomesLog();
                    l.setGroupId("demo");
                    l.setDomain("CUSTOMER");
                    l.setAction(String.valueOf(s[0]));
                    l.setContent(String.valueOf(s[1]));
                    l.setStaff(String.valueOf(s[2]));
                    l.setProcessedAt(LocalDateTime.now().minusHours(((Number) s[3]).longValue()));
                    em.persist(l);
                }
            }
            for (HomesLog l : em.createQuery("select l from HomesLog l where l.groupId='demo' and l.domain='CUSTOMER'", HomesLog.class).getResultList()) {
                if ("등록".equals(l.getAction())) {
                    l.setAction("고객-등록");
                    if (l.getContent() != null && !l.getContent().startsWith("고객 [") && !l.getContent().startsWith("계약고객 [")) {
                        l.setContent("고객 [" + l.getContent().trim() + "] 등록하였습니다.");
                    }
                } else if ("수정".equals(l.getAction())) {
                    l.setAction("고객-수정");
                    if (l.getContent() != null && !l.getContent().startsWith("고객 [")) {
                        l.setContent("고객 [" + l.getContent().trim() + "] 수정하였습니다.");
                    }
                } else if ("삭제".equals(l.getAction())) {
                    l.setAction("고객-삭제");
                } else if ("분류".equals(l.getAction()) || "고객-분류변경".equals(l.getAction())) {
                    l.setAction("고객-분류");
                }
            }
            // 장부이력 데모 보강
            long abookLogs = em.createQuery("select count(l) from HomesLog l where l.groupId='demo' and l.domain='ABOOKS'", Long.class).getSingleResult();
            if (abookLogs < 5) {
                Object[][] extra = {
                    {"간편장부-등록", "간편장부 [입금/일반] 등록하였습니다.", "홍길동", 1},
                    {"간편장부-수정", "간편장부 [출금/일반] 수정하였습니다.", "홍길동", 2},
                    {"간편장부-삭제", "간편장부 [카드출금/123] 삭제하였습니다.", "홍길동", 3},
                    {"간편장부-등록", "간편장부 [카드입금/일반] 등록하였습니다.", "김대표", 5},
                    {"간편장부-등록", "간편장부 [출금/123] 등록하였습니다.", "홍길동", 8},
                    {"간편장부-수정", "간편장부 [입금/일반] 수정하였습니다.", "홍길동", 12},
                };
                for (Object[] s : extra) {
                    HomesLog l = new HomesLog();
                    l.setGroupId("demo");
                    l.setDomain("ABOOKS");
                    l.setAction(String.valueOf(s[0]));
                    l.setContent(String.valueOf(s[1]));
                    l.setStaff(String.valueOf(s[2]));
                    l.setProcessedAt(LocalDateTime.now().minusHours(((Number) s[3]).longValue()));
                    em.persist(l);
                }
            }
            for (HomesLog l : em.createQuery("select l from HomesLog l where l.groupId='demo' and l.domain='ABOOKS'", HomesLog.class).getResultList()) {
                if ("등록".equals(l.getAction()) || "장부-등록".equals(l.getAction())) {
                    l.setAction("간편장부-등록");
                    if (l.getContent() != null && !l.getContent().startsWith("간편장부 [")) {
                        l.setContent("간편장부 [입금/일반] 등록하였습니다.");
                    }
                } else if ("수정".equals(l.getAction()) || "장부-수정".equals(l.getAction())) {
                    l.setAction("간편장부-수정");
                    if (l.getContent() != null && !l.getContent().startsWith("간편장부 [")) {
                        l.setContent("간편장부 [입금/일반] 수정하였습니다.");
                    }
                } else if ("삭제".equals(l.getAction()) || "장부-삭제".equals(l.getAction())) {
                    l.setAction("간편장부-삭제");
                    if (l.getContent() != null && !l.getContent().startsWith("간편장부 [")) {
                        l.setContent("간편장부 [출금/일반] 삭제하였습니다.");
                    }
                }
            }
        }
        ensurePendingDemoLogs();
    }

    /** 일정이력 원본 샘플(목록 48건) */
    private void ensurePendingDemoLogs() {
        for (HomesLog l : em.createQuery("select l from HomesLog l where l.groupId='demo' and l.domain='PENDING'", HomesLog.class).getResultList()) {
            if ("등록".equals(l.getAction())) {
                l.setAction("약속-등록");
                if (l.getContent() == null || !l.getContent().startsWith("약속 [")) {
                    String name = l.getContent() == null || l.getContent().isBlank() ? "일반" : l.getContent().trim();
                    l.setContent("약속 [" + name + "] 등록하였습니다.");
                }
            } else if ("수정".equals(l.getAction())) {
                l.setAction("약속-수정");
            } else if ("삭제".equals(l.getAction())) {
                l.setAction("약속-삭제");
            } else if ("처리".equals(l.getAction()) || "약속-처리".equals(l.getAction())) {
                l.setAction("약속-해결");
                if (l.getContent() != null && l.getContent().contains("해결 처리")) {
                    l.setContent(l.getContent().replace("해결 처리하였습니다.", "해결완료하였습니다."));
                } else if (l.getContent() == null || !l.getContent().startsWith("약속 [")) {
                    l.setContent("약속 [일반] 해결완료하였습니다.");
                }
            }
        }
        em.flush();
        long pendingLogs = em.createQuery("select count(l) from HomesLog l where l.groupId='demo' and l.domain='PENDING'", Long.class).getSingleResult();
        if (pendingLogs >= 40) return;
        for (HomesLog old : em.createQuery("select l from HomesLog l where l.groupId='demo' and l.domain='PENDING'", HomesLog.class).getResultList()) {
            em.remove(old);
        }
        em.flush();
        String[] types = {"일반", "약속1", "약속2"};
        LocalDateTime base = LocalDateTime.of(2024, 4, 1, 19, 49);
        for (int i = 0; i < 48; i++) {
            String type = types[i % types.length];
            HomesLog l = new HomesLog();
            l.setGroupId("demo");
            l.setDomain("PENDING");
            if (i % 3 == 1) {
                l.setAction("약속-해결");
                l.setContent("약속 [" + type + "] 해결완료하였습니다.");
            } else if (i % 9 == 0) {
                l.setAction("약속-수정");
                l.setContent("약속 [" + type + "] 수정하였습니다.");
            } else if (i % 13 == 0) {
                l.setAction("약속-삭제");
                l.setContent("약속 [" + type + "] 삭제하였습니다.");
            } else {
                l.setAction("약속-등록");
                l.setContent("약속 [" + type + "] 등록하였습니다.");
            }
            l.setStaff("홍길동");
            l.setProcessedAt(base.minusMinutes(i * 7L));
            em.persist(l);
        }
    }

    private void seedUnitCostsIfEmpty() {
        Long count = em.createQuery("select count(t) from UnitCostTable t where t.groupId='demo'", Long.class).getSingleResult();
        if (count > 0) return;
        List<Company> ins = em.createQuery("select c from Company c where c.groupId='demo' and c.type='IN'", Company.class).getResultList();
        Object[][] samples = {
            {"SKT", "SKT", "정책202103_테스트", 4, 11, 14, 2, null, null, null, 1, "표준"},
            {"KT", "KT", "KT기본정책", 2, 5, 7, 1, null, null, null, 1, "공시/선택구분"},
            {"LGU+", "LGT", "LG물류정책", 1, 3, null, null, null, null, null, 0, "표준"},
            {"SKT", "SKT2", "SKT2테스트", 3, 2, 1, null, null, null, null, 1, "표준"},
            {"LGU+", "LG물류", "LG물류", 2, null, null, null, null, null, null, 0, "표준"},
            {"KT", "KT", "선택약정표", 5, 4, 3, 2, 1, null, null, 1, "공시/선택구분"},
        };
        for (Object[] s : samples) {
            UnitCostTable t = new UnitCostTable();
            t.setGroupId("demo");
            t.setTelecom(String.valueOf(s[0]));
            t.setIncompanyName(String.valueOf(s[1]));
            if (!ins.isEmpty()) t.setIncompanyId(ins.getFirst().getId());
            t.setMemo(String.valueOf(s[2]));
            t.setPlanGroupA((Integer) s[3]);
            t.setPlanGroupB((Integer) s[4]);
            t.setPlanGroupC((Integer) s[5]);
            t.setPlanGroupD((Integer) s[6]);
            t.setPlanGroupE((Integer) s[7]);
            t.setPlanGroupF((Integer) s[8]);
            t.setPlanGroupG((Integer) s[9]);
            t.setPolicyCount((Integer) s[10]);
            t.setCategory(String.valueOf(s[11]));
            em.persist(t);
            em.flush();
            if ((Integer) s[10] > 0) {
                UnitCostPolicy p = new UnitCostPolicy();
                p.setGroupId("demo");
                p.setUnitCostId(t.getId());
                p.setPlanGroup("A");
                p.setModel("SM-");
                p.setPlanName("5GX 프라임");
                p.setAmount(new BigDecimal("100000"));
                em.persist(p);
            }
        }
    }

    private void seedOpenAdjustFields() {
        List<OpenRecord> opens = em.createQuery("select o from OpenRecord o where o.groupId='demo'", OpenRecord.class).getResultList();
        int i = 0;
        for (OpenRecord o : opens) {
            if (o.getDecltype() == null) o.setDecltype(i % 2 == 0 ? "단말할인" : "요금할인");
            if (o.getBasicprice1() == null) o.setBasicprice1(new BigDecimal("100000"));
            if (o.getBasicprice2() == null) o.setBasicprice2(new BigDecimal("50000"));
            if (o.getBasicprice3() == null) o.setBasicprice3(new BigDecimal("30000"));
            i++;
        }
    }

    private void seedBalancesIfEmpty() {
        Long count = em.createQuery("select count(b) from AfterBalance b where b.groupId='demo'", Long.class).getSingleResult();
        if (count > 0) return;
        List<Company> shops = em.createQuery("select c from Company c where c.groupId='demo' and c.type in ('SHOP','OUT')", Company.class).getResultList();
        List<Company> ins = em.createQuery("select c from Company c where c.groupId='demo' and c.type='IN'", Company.class).getResultList();
        if (shops.isEmpty()) return;
        Long inId = ins.isEmpty() ? null : ins.getFirst().getId();
        Object[][] samples = {
            {"정산차감", "그레이드 누락", "20000", "주*라", "010-****-3566", "D2"},
            {"정산추가", "택배비", "-100000", "남*섭", "010-****-1122", "늘푸른통신"},
            {"홈상품차감", "부가서비스 해지", "30000", "김*철", "010-****-5678", "늘붉은통신"},
            {"유심차감", "유심비 미수", "7700", "이*수", "010-****-1234", "스마트모바일"},
            {"정산추가", "테스트", "-3000", "박*영", "010-****-9876", "블루폰"},
            {"정산차감", "악세사리", "15000", "홍*동", "010-****-2222", "메인텔레콤"},
            {"정산차감", "서류미비 차감", "50000", "최*아", "010-****-7788", "늘푸른통신"},
            {"정산추가", "정책 보정", "-20000", "정*호", "010-****-9900", "D1"},
        };
        for (int i = 0; i < samples.length; i++) {
            Object[] s = samples[i];
            AfterBalance b = new AfterBalance();
            b.setGroupId("demo");
            b.setOutcompanyId(shops.get(i % shops.size()).getId());
            b.setIncompanyId(inId);
            b.setOutcompanyName(String.valueOf(s[5]));
            b.setGubun(String.valueOf(s[0]));
            b.setReason(String.valueOf(s[1]));
            b.setAmount(new BigDecimal(String.valueOf(s[2])));
            b.setCustomerName(String.valueOf(s[3]));
            b.setOpenphone(String.valueOf(s[4]));
            b.setTelecom(i % 3 == 0 ? "SKT" : (i % 3 == 1 ? "KT" : "LGU+"));
            b.setOutCategory("판매점");
            b.setOpendate(LocalDate.now().minusDays(20 + i * 5));
            b.setBasedate(LocalDate.now().minusDays(i * 2));
            b.setMemo(i % 3 == 0 ? "확인필요" : null);
            em.persist(b);
        }
    }

    private void seedReturnsEnrich() {
        List<UnreturnedPhone> rows = em.createQuery("select r from UnreturnedPhone r where r.groupId='demo'", UnreturnedPhone.class).getResultList();
        List<Company> ins = em.createQuery("select c from Company c where c.groupId='demo' and c.type='IN'", Company.class).getResultList();
        List<Company> shops = em.createQuery("select c from Company c where c.groupId='demo' and c.type in ('SHOP','OUT')", Company.class).getResultList();
        Long inId = ins.isEmpty() ? null : ins.getFirst().getId();
        Long shopId = shops.isEmpty() ? null : shops.getFirst().getId();
        for (UnreturnedPhone r : rows) {
            if (r.getTelecom() == null) r.setTelecom("SKT");
            if (r.getReturnStatus() == null) r.setReturnStatus("미반납");
            if (r.getIncompanyId() == null) r.setIncompanyId(inId);
        }
        if (rows.size() >= 5 || shopId == null) return;
        String[][] samples = {
            {"KT", "박*지", "010-****-6595", "미반납", "A125", "50000", "0"},
            {"SKT", "홍*동", "010-****-2222", "반납", "sm-g220", "1234", "10000"},
            {"LGU+", "김*수", "010-****-3344", "미반납", "SM-S928N", "IMEI9001", "30000"},
            {"SKT", "최*아", "010-****-7788", "반납", "A2860", "SN7788", ""},
            {"KT", "정*호", "010-****-9900", "미반납", "SM-A546", "A5469900", "15000"},
        };
        for (int i = 0; i < samples.length; i++) {
            String[] s = samples[i];
            UnreturnedPhone row = new UnreturnedPhone();
            row.setGroupId("demo");
            row.setOutcompanyId(shopId);
            row.setIncompanyId(inId);
            row.setOpendate(LocalDate.now().minusDays(5 + i * 3));
            row.setTelecom(s[0]);
            row.setCustomerName(s[1]);
            row.setOpenphone(s[2]);
            row.setReturnStatus(s[3]);
            row.setModel(s[4]);
            row.setSerial(s[5]);
            if (!s[6].isBlank()) row.setDeductAmount(new BigDecimal(s[6]));
            if ("반납".equals(s[3])) row.setReturndate(LocalDate.now().minusDays(i));
            em.persist(row);
        }
    }

    private void seedIndocsEnrich() {
        List<IncompleteDoc> docs = em.createQuery("select d from IncompleteDoc d where d.groupId='demo'", IncompleteDoc.class).getResultList();
        List<Company> ins = em.createQuery("select c from Company c where c.groupId='demo' and c.type='IN'", Company.class).getResultList();
        List<Company> shops = em.createQuery("select c from Company c where c.groupId='demo' and c.type='SHOP'", Company.class).getResultList();
        Long inId = ins.isEmpty() ? null : ins.getFirst().getId();
        Long shopId = shops.isEmpty() ? null : shops.getFirst().getId();
        for (IncompleteDoc d : docs) {
            if (d.getTelecom() == null) d.setTelecom("SKT");
            if (d.getStatus() == null) d.setStatus("미비");
            if (d.getIncompanyId() == null) d.setIncompanyId(inId);
        }
        if (docs.size() >= 3 || shopId == null) return;
        String[][] samples = {
            {"KT", "이*수", "010-****-1234", "인감증명서, 가족관계증명서", "50000", "추가서류 미제출"},
            {"LGU+", "박*영", "010-****-9876", "위임장", "20000", "대리개통 서류"},
        };
        for (int i = 0; i < samples.length; i++) {
            String[] s = samples[i];
            IncompleteDoc d = new IncompleteDoc();
            d.setGroupId("demo");
            d.setOutcompanyId(shopId);
            d.setIncompanyId(inId);
            d.setOpendate(LocalDate.now().minusDays(3L + i * 7));
            d.setTelecom(s[0]);
            d.setCustomerName(s[1]);
            d.setOpenphone(s[2]);
            d.setMissingDocs(s[3]);
            d.setDeductAmount(new BigDecimal(s[4]));
            d.setDeductReason(s[5]);
            d.setDeadline(LocalDate.now().plusDays(5L - i * 3));
            d.setStatus(i == 1 ? "마감임박" : "미비");
            em.persist(d);
        }
    }

    private void enrichReceptionProgressFields() {
        List<HomesReception> rows = em.createQuery(
                "select r from HomesReception r where r.groupId='demo'", HomesReception.class).getResultList();
        int i = 0;
        for (HomesReception r : rows) {
            if (r.getCustomerType() == null || r.getCustomerType().isBlank()) r.setCustomerType("public");
            if (r.getPaymentMethod() == null || r.getPaymentMethod().isBlank()) {
                String pt = r.getPaymentType();
                r.setPaymentMethod("카드".equals(pt) ? "card" : "지로".equals(pt) ? "paper" : "전화납부".equals(pt) ? "telephone" : "transfer");
            }
            if (r.getProductType() == null || r.getProductType().isBlank()) {
                String cat = r.getProductCategory();
                r.setProductType("전화".equals(cat) ? "e02" : "TV".equals(cat) ? "e03" : "렌탈".equals(cat) || (cat != null && (cat.contains("정수") || cat.contains("비데") || cat.contains("공기"))) ? "e04" : "e01");
            }
            if (r.getEmail() == null || r.getEmail().isBlank()) {
                r.setEmail("sample" + (++i) + "@example.com");
            }
            if (r.getAddress() == null || r.getAddress().isBlank()) {
                r.setZipcode("06236");
                r.setAddress("서울특별시 강남구 테헤란로 " + (10 + i));
                r.setAddressDetail((100 + i) + "호");
            }
            if (r.getIdentifyNumber() == null || r.getIdentifyNumber().isBlank()) {
                r.setIdentifyNumber("900101-1******");
            }
            if (r.getPostIt() == null || r.getPostIt().isBlank()) r.setPostIt("샘플메모" + (i % 50 + 1));
            if (r.getBranchPhone() == null || r.getBranchPhone().isBlank()) r.setBranchPhone("1599-2889");
            if (r.getTel() == null || r.getTel().isBlank()) r.setTel("02-100" + i);
            if (r.getGiftSended() == null && r.getGiftDate() != null) r.setGiftSended(r.getGiftDate());
            if (r.getGiftCashAmount() == null && r.getAmount() != null
                    && r.getGiftStatus() != null && !"미지급".equals(r.getGiftStatus()) && !"없음".equals(r.getGiftCategory())) {
                r.setGiftCashAmount(r.getAmount());
            }
            if (r.getIspName() == null || r.getIspName().isBlank()) r.setIspName(r.getCarrier());
            if (r.getProcessor() == null || r.getProcessor().isBlank()) r.setProcessor("본사");
        }
    }

    private void seedReceptionIspsIfEmpty() {
        if (em.createQuery("select count(i) from HomesReceptionIsp i where i.groupId='demo'", Long.class).getSingleResult() > 0) {
            return;
        }
        Object[][] isps = {
            {"LG USIM", "LGU+", 1, false},
            {"LGU+ 온라인", "LGU+", 2, false},
            {"LGU+ (T일반)", "LGU+", 3, false},
            {"KT USIM", "KT", 4, false},
            {"KT일반 (강북)", "KT", 5, false},
            {"KT일반 (강남)", "KT", 6, false},
            {"KT일반 (강서)", "KT", 7, false},
            {"KT일반 (경남)", "KT", 8, false},
            {"KT일반 (경북)", "KT", 9, false},
            {"KT일반 (충청)", "KT", 10, false},
            {"KT일반 (전라)", "KT", 11, false},
            {"SKB USIM", "SKB", 12, false},
            {"SKB다이렉트(서울/경기)", "SKB", 13, false},
            {"SKB다이렉트(부산/경남)", "SKB", 14, false},
            {"SKB다이렉트(대구/경북)", "SKB", 15, false},
            {"SKB다이렉트(충청/강원)", "SKB", 16, false},
            {"SKB다이렉트(전라/제주)", "SKB", 17, false},
            {"SKB POP", "SKB", 18, false},
            {"SKT온/한가족(서울/경기)", "SKT", 19, true},
            {"SKT온/한가족(부산/경남)", "SKT", 20, true},
            {"SKT온/한가족(대구/경북)", "SKT", 21, true},
            {"SKT온/한가족(대전/충청/강원)", "SKT", 22, true},
            {"SKT온/한가족(전라/제주)", "SKT", 23, true},
            {"SK매직", "SK매직", 24, false},
            {"LG렌탈", "LG렌탈", 25, false},
            {"Skylife(전국)", "Skylife", 26, false},
        };
        for (Object[] row : isps) {
            HomesReceptionIsp isp = new HomesReceptionIsp();
            isp.setGroupId("demo");
            isp.setName(String.valueOf(row[0]));
            isp.setTelecom(String.valueOf(row[1]));
            isp.setSeq((Integer) row[2]);
            isp.setActive(true);
            isp.setIsSktb((Boolean) row[3]);
            em.persist(isp);
            em.flush();

            boolean rental = "SK매직".equals(isp.getTelecom()) || "LG렌탈".equals(isp.getTelecom());
            String[][] products = rental
                    ? new String[][]{{"e04", isp.getName() + " 기본렌탈"}, {"e04", isp.getName() + " 프리미엄"}}
                    : new String[][]{
                        {"e01", isp.getTelecom() + " 인터넷 기본"},
                        {"e01", isp.getTelecom() + " 인터넷 프리미엄"},
                        {"e03", isp.getTelecom() + " TV"},
                        {"e02", isp.getTelecom() + " 집전화"},
                    };
            for (String[] p : products) {
                HomesReceptionIspProduct prod = new HomesReceptionIspProduct();
                prod.setGroupId("demo");
                prod.setIspId(isp.getId());
                prod.setProductType(p[0]);
                prod.setName(p[1]);
                prod.setActive(true);
                em.persist(prod);
            }
            for (String agName : List.of("24개월", "36개월", "48개월", "60개월")) {
                HomesReceptionIspAgreement ag = new HomesReceptionIspAgreement();
                ag.setGroupId("demo");
                ag.setIspId(isp.getId());
                ag.setName(agName);
                ag.setActive(true);
                em.persist(ag);
            }
        }
    }

    private Company company(String type, String name, String manager, String phone) {
        Company c = new Company();
        c.setGroupId("demo");
        c.setType(type);
        c.setName(name);
        c.setManagerName(manager);
        c.setPhone(phone);
        c.setActive(true);
        em.persist(c);
        em.flush();
        return c;
    }

    private Stock stock(String gubun, String telecom, String model, String color, String serial,
                        String state, Long inId, Long outId, String price) {
        Stock s = new Stock();
        s.setGroupId("demo");
        s.setGubun(gubun);
        s.setTelecom(telecom);
        s.setTelcompany(telecom);
        s.setModel(model);
        s.setColor(color);
        s.setSerial(serial);
        s.setBarcode(serial);
        s.setCond("정상");
        s.setPay("할부");
        s.setState(state);
        s.setOutcode(state.equals("OUT") || state.equals("OPEN") ? "21" : "10");
        s.setIncompanyId(inId);
        s.setOutcompanyId(outId);
        s.setIndate(LocalDate.now().minusDays(5));
        if (outId != null) s.setOutdate(LocalDate.now().minusDays(1));
        s.setProcessDate(LocalDate.now().minusDays(1));
        s.setProcessor("데모 관리자");
        s.setInprice(new BigDecimal(price));
        s.setUserid("demo");
        s.setProcid("demo");
        s.setUid("stk-" + UUID.randomUUID());
        em.persist(s);
        return s;
    }
}
