#!/usr/bin/env python3
"""
统一搜索服务（端口8000）
/ → 中项网  (/root/cceup.db)
/znlh → 中能联合  (/home/ccbuild/znlh.db)
/zc → 中策大数据  (/home/ccbuild/zc.db)
"""

import http.server, sqlite3, urllib.parse, re, os

CCEUP_DB = '/root/cceup.db'
ZNLH_DB = '/home/ccbuild/znlh.db'
ZC_DB = '/home/ccbuild/zc.db'


def esc(s):
    if s is None: return ''
    return str(s).replace('&','&amp;').replace('<','&lt;').replace('>','&gt;').replace('"','&quot;')


# ══════════════════════════════════════════════
#  ZC 数据库
# ══════════════════════════════════════════════

def zc_search(q, page=1, per=20):
    db = sqlite3.connect(ZC_DB); db.row_factory = sqlite3.Row
    conds, params = [], []
    if q:
        t = '%'+q+'%'
        conds.append('(project_id LIKE ? OR project_name LIKE ? OR industry LIKE ? OR province LIKE ? OR city LIKE ?)')
        params = [t]*5
    wh = 'WHERE '+' AND '.join(conds) if conds else ''
    total = db.execute('SELECT COUNT(*) FROM zc_projects '+wh, params).fetchone()[0]
    rows = [dict(r) for r in db.execute('SELECT * FROM zc_projects '+wh+' ORDER BY publish_date DESC, project_id LIMIT ? OFFSET ?', params+[per,(page-1)*per])]
    db.close()
    return total, rows

def zc_detail(pid):
    db = sqlite3.connect(ZC_DB); db.row_factory = sqlite3.Row
    r = db.execute('SELECT * FROM zc_projects WHERE project_id=?',(pid,)).fetchone()
    if not r: db.close(); return None
    p = dict(r)
    p['contacts'] = [dict(r) for r in db.execute('SELECT * FROM zc_contacts WHERE project_id=? ORDER BY id',(pid,))]
    db.close()
    return p

# ══════════════════════════════════════════════
#  ZNLH 数据库
# ══════════════════════════════════════════════

def znlh_search(q, page=1, per=20):
    db = sqlite3.connect(ZNLH_DB); db.row_factory = sqlite3.Row
    conds, params = [], []
    if q:
        t = '%'+q+'%'
        conds.append('(project_id LIKE ? OR project_name LIKE ? OR owner_company LIKE ? OR industry LIKE ? OR province LIKE ? OR city LIKE ?)')
        params = [t]*6
    wh = 'WHERE '+' AND '.join(conds) if conds else ''
    total = db.execute('SELECT COUNT(*) FROM znlh_projects '+wh, params).fetchone()[0]
    rows = [dict(r) for r in db.execute('SELECT * FROM znlh_projects '+wh+' ORDER BY publish_date DESC, project_id LIMIT ? OFFSET ?', params+[per,(page-1)*per])]
    db.close()
    return total, rows

def znlh_detail(pid):
    db = sqlite3.connect(ZNLH_DB); db.row_factory = sqlite3.Row
    r = db.execute('SELECT * FROM znlh_projects WHERE project_id=?',(pid,)).fetchone()
    if not r: db.close(); return None
    p = dict(r)
    p['contacts'] = [dict(r) for r in db.execute('SELECT * FROM znlh_contacts WHERE project_id=? ORDER BY id',(pid,))]
    db.close()
    return p

# ══════════════════════════════════════════════
#  CCEUP 数据库
# ══════════════════════════════════════════════

def cceup_search(q, page=1, per=20):
    if not os.path.exists(CCEUP_DB):
        return 0, []
    db = sqlite3.connect(CCEUP_DB); db.row_factory = sqlite3.Row
    conds, params = [], []
    if q:
        t = '%'+q+'%'
        conds.append('(project_id LIKE ? OR project_name LIKE ? OR owner_company LIKE ? OR industry LIKE ? OR province LIKE ? OR city LIKE ?)')
        params = [t]*6
    wh = 'WHERE '+' AND '.join(conds) if conds else ''
    total = db.execute('SELECT COUNT(*) FROM cceup_projects '+wh, params).fetchone()[0]
    rows = [dict(r) for r in db.execute('SELECT * FROM cceup_projects '+wh+' ORDER BY publish_date DESC, project_id LIMIT ? OFFSET ?', params+[per,(page-1)*per])]
    db.close()
    return total, rows

def cceup_detail(pid):
    if not os.path.exists(CCEUP_DB):
        return None
    db = sqlite3.connect(CCEUP_DB); db.row_factory = sqlite3.Row
    r = db.execute('SELECT * FROM cceup_projects WHERE project_id=?',(pid,)).fetchone()
    if not r: db.close(); return None
    p = dict(r)
    p['contacts'] = [dict(r) for r in db.execute('SELECT * FROM cceup_contacts WHERE project_id=? ORDER BY id',(pid,))]
    db.close()
    return p

# ══════════════════════════════════════════════
#  HTML 渲染
# ══════════════════════════════════════════════

HEAD = '''<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>{title}</title>
<style>
*{{margin:0;padding:0;box-sizing:border-box}}
body{{font-family:-apple-system,'Microsoft YaHei',sans-serif;background:#f5f5f5;color:#333}}
.w{{max-width:1200px;margin:0 auto;padding:20px}}
h1{{font-size:22px;margin-bottom:10px;color:#1a1a2e}}
.nav{{margin-bottom:20px;display:flex;gap:4px}}
.nav a{{padding:6px 16px;background:#fff;border:1px solid #ddd;border-radius:6px;text-decoration:none;color:#555;font-size:14px}}
.nav a.act{{background:#4361ee;color:#fff;border-color:#4361ee}}
.sb{{display:flex;gap:10px;margin-bottom:20px}}
.sb input{{flex:1;padding:10px 15px;border:1px solid #ddd;border-radius:6px;font-size:15px}}
.sb button{{padding:10px 24px;background:#4361ee;color:#fff;border:none;border-radius:6px;cursor:pointer;font-size:15px}}
.st{{color:#666;font-size:14px;margin-bottom:15px}}
.cd{{background:#fff;border-radius:8px;padding:16px 20px;margin-bottom:10px;box-shadow:0 1px 3px rgba(0,0,0,.08);cursor:pointer}}
.cd:hover{{box-shadow:0 2px 8px rgba(0,0,0,.12)}}
.tt{{font-size:16px;font-weight:600;color:#1a1a2e;margin-bottom:6px}}
.meta{{font-size:13px;color:#666;display:flex;gap:16px;flex-wrap:wrap}}
.bdg{{display:inline-block;padding:2px 8px;border-radius:4px;font-size:12px}}
.b1{{background:#e8f4fd;color:#1976d2}}
.b2{{background:#fff3e0;color:#e65100}}
.b3{{background:#e8f5e9;color:#2e7d32}}
.pg{{display:flex;justify-content:center;gap:8px;margin-top:20px}}
.pg a{{padding:6px 14px;background:#fff;border:1px solid #ddd;border-radius:6px;text-decoration:none;color:#333;font-size:14px}}
.pg a.ac{{background:#4361ee;color:#fff;border-color:#4361ee}}
a.bk{{display:inline-block;margin-bottom:16px;color:#4361ee;text-decoration:none;font-size:14px}}
.dh{{background:#fff;border-radius:8px;padding:24px;margin-bottom:16px;box-shadow:0 1px 3px rgba(0,0,0,.08)}}
.dh h2{{font-size:20px;margin-bottom:12px}}
.dg{{display:grid;grid-template-columns:1fr 1fr;gap:8px 32px;font-size:14px}}
.dg .it{{display:flex}}
.dg .lb{{color:#888;min-width:90px;flex-shrink:0}}
.ds{{background:#fff;border-radius:8px;padding:20px 24px;margin-bottom:16px;box-shadow:0 1px 3px rgba(0,0,0,.08)}}
.ds h3{{font-size:16px;color:#1a1a2e;margin-bottom:10px;padding-bottom:6px;border-bottom:2px solid #4361ee}}
.ds .ct{{font-size:14px;line-height:1.7;color:#444;white-space:pre-wrap}}
.cc{{border:1px solid #e8e8e8;border-radius:8px;padding:16px;margin-bottom:12px;background:#fafafa}}
.cc .cm{{font-size:15px;font-weight:600;color:#1a1a2e;margin-bottom:4px}}
.cc .fd{{display:grid;grid-template-columns:auto 1fr;gap:4px 12px;font-size:14px;margin-top:8px}}
.cc .fd .cl{{color:#888}}
</style></head><body><div class="w">'''

NAV = '''<div class="nav">
<a href="/" class="{c1}">中项网</a>
<a href="/znlh/" class="{c2}">中能联合</a>
<a href="/zc/" class="{c3}">中策大数据</a>
</div>'''

TAIL = '</div></body></html>'


def nav_html(active):
    return NAV.format(c1='act' if active=='cceup' else '',
                      c2='act' if active=='znlh' else '',
                      c3='act' if active=='zc' else '')


def render_list(db, title, active, q, page, total, rows, fields):
    tp = max(1,(total+19)//20)
    qp = '&q='+urllib.parse.quote(q) if q else ''
    prefix = '/'+db
    h = HEAD.format(title=title)
    h += '<h1>'+title+'</h1>'+nav_html(active)
    h += '<form class="sb" method="get" action="'+prefix+'/"><input type="text" name="q" placeholder="搜索项目…" value="'+esc(q)+'"><button>搜索</button></form>'
    h += '<div class="st">共 '+str(total)+' 个项目'+('，搜索"'+esc(q)+'"' if q else '')+'</div>'
    for r in rows:
        pid = esc(r.get('project_id',''))
        name = esc(r.get('project_name','') or r.get('owner_company','') or '')
        h += '<div class="cd" onclick="location.href=\''+prefix+'/project/'+pid+'\'"><div class="tt">'+name+'</div><div class="meta">'
        h += '<span>#'+pid+'</span>'
        for f in fields:
            v = r.get(f[0],'')
            if v:
                h += '<span class="bdg '+f[1]+'">'+esc(v)+'</span>'
        if r.get('province'):
            h += '<span>'+esc(r['province'])+('/'+esc(r['city']) if r.get('city') else '')+'</span>'
        if r.get('total_investment') or r.get('budget'):
            h += '<span>'+esc(r.get('total_investment','') or r.get('budget',''))+'</span>'
        if r.get('publish_date'):
            h += '<span>'+esc(r['publish_date'])+'</span>'
        h += '</div></div>'
    if tp>1:
        h += '<div class="pg">'
        for p in range(1, min(tp+1,21)):
            h += '<a class="'+('ac' if p==page else '')+'" href="'+prefix+'/?page='+str(p)+qp+'">'+str(p)+'</a>'
        h += '</div>'
    return h+TAIL


def render_fields(h, p, field_list):
    for lbl, key in field_list:
        v = p.get(key,'')
        if v and v!='一一' and v!='——':
            h += '<div class="it"><span class="lb">'+lbl+'：</span><span>'+esc(v)+'</span></div>'
    return h


def render_contacts(h, contacts):
    if contacts:
        h += '<div class="ds"><h3>项目联系人</h3>'
        for c in contacts:
            h += '<div class="cc"><div class="cm">'+esc(c.get('company','') or c.get('owner_company',''))+'</div><div class="fd">'
            if c.get('contact_name'): h += '<span class="cl">姓名：</span><span>'+esc(c['contact_name'])+'</span>'
            if c.get('department'): h += '<span class="cl">部门：</span><span>'+esc(c['department'])+'</span>'
            if c.get('position'): h += '<span class="cl">职务：</span><span>'+esc(c['position'])+'</span>'
            if c.get('phone'): h += '<span class="cl">手机：</span><span>'+esc(c['phone'])+'</span>'
            if c.get('address'): h += '<span class="cl">地址：</span><span>'+esc(c['address'])+'</span>'
            if c.get('remarks') and c['remarks'] not in ('一一','——',''):
                h += '<span class="cl">备注：</span><span>'+esc(c['remarks'])+'</span>'
            h += '</div></div>'
        h += '</div>'
    return h


# ══════════════════════════════════════════════
#  Route handlers
# ══════════════════════════════════════════════

def handle_zc(path, params):
    q = params.get('q',[''])[0].strip()
    page = int(params.get('page',['1'])[0])
    if path.startswith('/project/'):
        pid = path[9:]
        p = zc_detail(pid)
        if not p:
            return 404, '<html><body><h1>404</h1></body></html>'
        h = HEAD.format(title='中策大数据 - '+esc(p.get('project_name','')))
        h += nav_html('zc') + '<a class="bk" href="/zc/">← 返回列表</a>'
        h += '<div class="dh"><h2>'+esc(p.get('project_name',''))+'</h2><div class="dg">'
        h = render_fields(h, p, [
            ('项目编号','project_id'),('版本类型','version_type'),('发布时间','publish_date'),
            ('项目阶段','phase'),('建设周期','construction_period'),('总投资额','total_investment'),
            ('工程类型','project_type'),('甲方性质','owner_nature'),('所属行业','industry'),
            ('项目规模','scale'),('省份','province'),('城市','city'),('详细地址','detail_address'),
            ('建筑面积','building_area'),('占地面积','land_area'),('建筑层数','floors'),
            ('外资参与','foreign_investment'),('装修','decoration'),('钢结构','steel_structure'),
            ('外墙材料','exterior_wall'),('车库停车位','parking'),('电梯','elevator'),
            ('空调','air_conditioning'),('新风系统','fresh_air'),('供暖方式','heating'),
            ('装配式建筑','prefab'),('被动房','passive_house'),
        ])
        h += '</div></div>'
        if p.get('construction_content'):
            h += '<div class="ds"><h3>建设内容</h3><div class="ct">'+esc(p['construction_content'])+'</div></div>'
        if p.get('equipment_list'):
            h += '<div class="ds"><h3>设备清单</h3><div class="ct">'+esc(p['equipment_list'])+'</div></div>'
        if p.get('schedule_overview'):
            h += '<div class="ds"><h3>工期概述</h3><div class="ct">'+esc(p['schedule_overview'])+'</div></div>'
        h = render_contacts(h, p.get('contacts',[]))
        return 200, h+TAIL
    else:
        total, rows = zc_search(q, page)
        h = render_list('zc', '中策大数据', 'zc', q, page, total, rows,
                        [('phase','b1'),('scale','b2'),('project_type','b3')])
        return 200, h


def handle_znlh(path, params):
    q = params.get('q',[''])[0].strip()
    page = int(params.get('page',['1'])[0])
    if path.startswith('/project/'):
        pid = path[9:]
        p = znlh_detail(pid)
        if not p:
            return 404, '<html><body><h1>404</h1></body></html>'
        h = HEAD.format(title='中能联合 - '+esc(p.get('project_name','')))
        h += nav_html('znlh') + '<a class="bk" href="/znlh/">← 返回列表</a>'
        h += '<div class="dh"><h2>'+esc(p.get('project_name',''))+'</h2><div class="dg">'
        h = render_fields(h, p, [
            ('项目编号','project_id'),('当前阶段','phase'),('总投资','budget'),
            ('所属行业','industry'),('区域','region'),('省份','province'),('城市','city'),
            ('工程类型','nature'),('占地面积','area'),('采购情况','purchase_status'),
            ('竣工日期','completion_date'),('权重','weight'),('业主类型','owner_type'),
            ('发布日期','publish_date'),('资金情况','funding_status'),('更新时间','update_date'),
        ])
        h += '</div></div>'
        # Enterprise info
        ent = [('企业名称','owner_company'),('注册地址','registered_address'),('注册资金','registered_capital'),
               ('企业负责人','company_contact'),('主营业务','business_scope')]
        has_ent = any(p.get(k) for _,k in ent)
        if has_ent:
            h += '<div class="ds"><h3>业主信息</h3><div class="dg">'
            for lbl,k in ent:
                v = p.get(k,'')
                if v:
                    h += '<div class="it" style="grid-column:span 2"><span class="lb">'+lbl+'：</span><span>'+esc(v)+'</span></div>'
            h += '</div></div>'
        # Detail 1-5
        for lbl,k in [('1.建设背景','background'),('2.建设内容','construction_content'),
                       ('3.工艺路线','process_route'),('4.建设地点','construction_location'),('5.社会效益','social_benefits')]:
            v = p.get(k,'')
            if v:
                h += '<div class="ds"><h3>'+lbl+'</h3><div class="ct">'+esc(v)+'</div></div>'
        # Equipment
        eq = [('工艺设备','equipment_list'),('配套设施设备','supporting_equipment'),('客户所需设备','client_needed_equipment')]
        has_eq = any(p.get(k) for _,k in eq)
        if has_eq:
            h += '<div class="ds"><h3>设备清单</h3>'
            for lbl,k in eq:
                v = p.get(k,'')
                if v:
                    h += '<p><strong>'+lbl+'：</strong><br>'+esc(v)+'</p>'
            h += '</div>'
        if p.get('project_progress'):
            h += '<div class="ds"><h3>项目进展</h3><div class="ct">'+esc(p['project_progress'])+'</div></div>'
        if p.get('detail'):
            h += '<div class="ds"><h3>特殊说明</h3><div class="ct">'+esc(p['detail'])+'</div></div>'
        h = render_contacts(h, p.get('contacts',[]))
        return 200, h+TAIL
    else:
        total, rows = znlh_search(q, page)
        h = render_list('znlh', '中能联合', 'znlh', q, page, total, rows,
                        [('phase','b1'),('weight','b2'),('nature','b3')])
        return 200, h


def handle_cceup(path, params):
    q = params.get('q',[''])[0].strip()
    page = int(params.get('page',['1'])[0])
    if path.startswith('/project/'):
        pid = path[9:]
        p = cceup_detail(pid)
        if not p:
            return 404, '<html><body><h1>404</h1></body></html>'
        h = HEAD.format(title='中项网 - '+esc(p.get('project_name','') or p.get('owner_company','')))
        h += nav_html('cceup') + '<a class="bk" href="/">← 返回列表</a>'
        h += '<div class="dh"><h2>'+esc(p.get('project_name','') or p.get('owner_company',''))+'</h2><div class="dg">'
        h = render_fields(h, p, [
            ('项目编号','project_id'),('项目阶段','phase'),('投资金额','budget'),
            ('所属行业','industry'),('省份','province'),('城市','city'),
            ('工程类型','nature'),('业主类型','owner_type'),('发布时间','publish_date'),
        ])
        h += '</div></div>'
        if p.get('overview'):
            h += '<div class="ds"><h3>项目概况</h3><div class="ct">'+esc(p['overview'])+'</div></div>'
        if p.get('progress'):
            h += '<div class="ds"><h3>项目进展</h3><div class="ct">'+esc(p['progress'])+'</div></div>'
        if p.get('detail'):
            h += '<div class="ds"><h3>项目详情</h3><div class="ct">'+esc(p['detail'])+'</div></div>'
        h = render_contacts(h, p.get('contacts',[]))
        return 200, h+TAIL
    else:
        total, rows = cceup_search(q, page)
        h = render_list('', '中项网', 'cceup', q, page, total, rows,
                        [('phase','b1'),('nature','b3')])
        return 200, h


# ══════════════════════════════════════════════
#  HTTP Server
# ══════════════════════════════════════════════

class UnifiedHandler(http.server.BaseHTTPRequestHandler):
    def do_GET(self):
        p = urllib.parse.urlparse(self.path)
        params = urllib.parse.parse_qs(p.query)
        path = p.path.rstrip('/') or '/'
        try:
            if path.startswith('/zc'):
                sub = path[3:] or '/'
                code, body = handle_zc(sub, params)
            elif path.startswith('/znlh'):
                sub = path[5:] or '/'
                code, body = handle_znlh(sub, params)
            elif path.startswith('/project/'):
                # backward compat: /project/XXX -> CCEUP
                code, body = handle_cceup(path, params)
            else:
                code, body = handle_cceup(path, params)
            b = body.encode()
            self.send_response(code)
            self.send_header('Content-Type','text/html; charset=utf-8')
            self.send_header('Content-Length',str(len(b)))
            self.end_headers()
            self.wfile.write(b)
        except Exception as e:
            import traceback
            err = '<pre>'+esc(traceback.format_exc())+'</pre>'
            b = err.encode()
            self.send_response(500)
            self.send_header('Content-Type','text/html; charset=utf-8')
            self.send_header('Content-Length',str(len(b)))
            self.end_headers()
            self.wfile.write(b)
    def log_message(self,*a): pass


if __name__ == '__main__':
    print('Unified search on :8000  [/ /zc/ /znlh/]')
    http.server.HTTPServer(('0.0.0.0',8000),UnifiedHandler).serve_forever()
