import { useState } from 'react';
import {
  Card,
  Checkbox,
  Col,
  Empty,
  message,
  Modal,
  Row,
  Space,
  Table,
  Tag,
  Button,
} from 'antd';
import { useQuery, useQueryClient } from '@tanstack/react-query';
import PageContainer from '@/components/common/PageContainer';
import { roleApi, RoleVO } from '@/api/user';
import { menuApi, MenuResp } from '@/api/menu';

const PERMS = ['READ', 'CREATE', 'UPDATE', 'DELETE', 'APPROVE', 'EXPORT'] as const;
const PERM_LABELS: Record<string, string> = {
  READ: '조회',
  CREATE: '등록',
  UPDATE: '수정',
  DELETE: '삭제',
  APPROVE: '승인',
  EXPORT: '엑셀',
};

type PermKey = string; // "${menuId}:${permCode}"

interface FlatMenuItem {
  menuId: number;
  menuCode: string;
  menuName: string;
  menuType: 'DIRECTORY' | 'PAGE' | 'LINK';
  indent: number; // 0 = top-level directory, 1 = child page
}

function flattenMenu(nodes: MenuResp[], indent = 0): FlatMenuItem[] {
  const out: FlatMenuItem[] = [];
  for (const n of nodes) {
    out.push({
      menuId: n.menuId,
      menuCode: n.menuCode,
      menuName: n.menuName,
      menuType: n.menuType,
      indent,
    });
    if (n.children?.length) {
      out.push(...flattenMenu(n.children, indent + 1));
    }
  }
  return out;
}

export default function RoleList() {
  const qc = useQueryClient();
  const [selected, setSelected] = useState<RoleVO | null>(null);
  const [granted, setGranted] = useState<Set<PermKey>>(new Set());
  const [saving, setSaving] = useState(false);

  const { data: roles = [] } = useQuery({
    queryKey: ['role', 'list'],
    queryFn: roleApi.list,
  });

  const { data: tree = [] } = useQuery({
    queryKey: ['menu', 'tree'],
    queryFn: menuApi.tree,
  });

  const flatMenu = flattenMenu(tree);

  const selectRole = async (r: RoleVO) => {
    setSelected(r);
    const perms = await roleApi.permissions(r.roleId);
    const set = new Set<PermKey>();
    perms.forEach((p) => {
      if (p.isGranted === 'Y') set.add(`${p.menuId}:${p.permCode}`);
    });
    setGranted(set);
  };

  const toggle = (menuId: number, permCode: string) => {
    const key = `${menuId}:${permCode}`;
    const next = new Set(granted);
    next.has(key) ? next.delete(key) : next.add(key);
    setGranted(next);
  };

  const toggleAll = () => {
    const pages = flatMenu.filter((m) => m.menuType !== 'DIRECTORY');
    const allKeys = pages.flatMap((m) => PERMS.map((p) => `${m.menuId}:${p}`));
    const allGranted = allKeys.every((k) => granted.has(k));
    if (allGranted) {
      setGranted(new Set());
    } else {
      setGranted(new Set(allKeys));
    }
  };

  const save = () => {
    if (!selected) return;
    Modal.confirm({
      title: '권한 저장',
      content: `[${selected.roleName}] 역할의 권한 매트릭스를 저장하시겠습니까?`,
      okText: '저장',
      cancelText: '취소',
      onOk: async () => {
        setSaving(true);
        try {
          const list = Array.from(granted).map((k) => {
            const [menuId, permCode] = k.split(':');
            return { menuId: Number(menuId), permCode, isGranted: 'Y' as const };
          });
          await roleApi.savePermissions(selected.roleId, list);
          message.success('권한 매트릭스 저장 완료');
          qc.invalidateQueries({ queryKey: ['menu'] });
        } finally {
          setSaving(false);
        }
      },
    });
  };

  const allPages = flatMenu.filter((m) => m.menuType !== 'DIRECTORY');
  const allKeys = allPages.flatMap((m) => PERMS.map((p) => `${m.menuId}:${p}`));
  const allChecked = allKeys.length > 0 && allKeys.every((k) => granted.has(k));

  return (
    <PageContainer title="역할 / 권한">
      <Row gutter={16}>
        {/* 역할 목록 */}
        <Col flex="300px">
          <Card title="역할 목록" size="small">
            <Table<RoleVO>
              rowKey="roleId"
              dataSource={roles}
              size="small"
              pagination={false}
              scroll={{ y: 600 }}
              onRow={(r) => ({
                onClick: () => selectRole(r),
                style: { cursor: 'pointer' },
              })}
              rowClassName={(r) =>
                r.roleId === selected?.roleId ? 'ant-table-row-selected' : ''
              }
              columns={[
                { title: '코드', dataIndex: 'roleCode', width: 110, ellipsis: true },
                { title: '이름', dataIndex: 'roleName', ellipsis: true },
                {
                  title: '활성',
                  dataIndex: 'isActive',
                  width: 55,
                  align: 'center',
                  render: (v: string) => (
                    <Tag color={v === 'Y' ? 'green' : 'default'}>
                      {v === 'Y' ? 'Y' : 'N'}
                    </Tag>
                  ),
                },
              ]}
            />
          </Card>
        </Col>

        {/* 권한 매트릭스 */}
        <Col flex="1">
          <Card
            title={
              selected
                ? `권한 매트릭스 — ${selected.roleName}`
                : '권한 매트릭스'
            }
            size="small"
            extra={
              selected && (
                <Space>
                  <Button size="small" onClick={toggleAll}>
                    {allChecked ? '전체 해제' : '전체 선택'}
                  </Button>
                  <Button
                    type="primary"
                    size="small"
                    loading={saving}
                    onClick={save}
                  >
                    저장
                  </Button>
                </Space>
              )
            }
          >
            {!selected ? (
              <Empty description="좌측 역할을 클릭하세요" />
            ) : (
              <Table<FlatMenuItem>
                size="small"
                pagination={false}
                rowKey="menuId"
                dataSource={flatMenu}
                scroll={{ y: 560 }}
                columns={[
                  {
                    title: '메뉴',
                    dataIndex: 'menuName',
                    width: 220,
                    render: (name: string, row: FlatMenuItem) => (
                      <span
                        style={{
                          paddingLeft: row.indent * 12,
                          fontWeight: row.menuType === 'DIRECTORY' ? 600 : 400,
                          color: row.menuType === 'DIRECTORY' ? '#1677ff' : undefined,
                        }}
                      >
                        {name}
                      </span>
                    ),
                  },
                  ...PERMS.map((p) => ({
                    title: PERM_LABELS[p],
                    key: p,
                    width: 64,
                    align: 'center' as const,
                    render: (_: unknown, m: FlatMenuItem) => {
                      if (m.menuType === 'DIRECTORY') return null;
                      return (
                        <Checkbox
                          checked={granted.has(`${m.menuId}:${p}`)}
                          onChange={() => toggle(m.menuId, p)}
                        />
                      );
                    },
                  })),
                ]}
              />
            )}
          </Card>
        </Col>
      </Row>
    </PageContainer>
  );
}
