-- 005: tenant admin writes; requires 003 signed RLS context, 004 login facade
BEGIN;
SET LOCAL search_path TO optikrapor,pg_catalog;
CREATE OR REPLACE FUNCTION optikrapor.manage_company(p_id bigint,p_name text,p_phone text,p_email text)
RETURNS void LANGUAGE plpgsql SECURITY DEFINER SET search_path=pg_catalog,optikrapor AS $$
DECLARE a record;
BEGIN
 SELECT * INTO a FROM optikrapor.auth_claims() LIMIT 1;
 IF a.company_id IS NULL OR a.company_id <> p_id OR NOT EXISTS (
   SELECT 1 FROM optikrapor.user_memberships m JOIN optikrapor.roles r ON r.id=m.role_id
   WHERE m.user_id=a.user_id AND m.company_id=p_id AND m.branch_id IS NULL
   AND m.is_active AND r.code='company_admin'
 ) THEN RAISE EXCEPTION 'Access denied' USING ERRCODE='42501'; END IF;
 IF length(trim(coalesce(p_name,''))) NOT BETWEEN 2 AND 200 OR length(coalesce(p_phone,''))>35
 OR length(coalesce(p_email,''))>254 THEN RAISE EXCEPTION 'Invalid fields'; END IF;
 UPDATE optikrapor.companies SET name=trim(p_name),phone=nullif(trim(p_phone),''),email=nullif(trim(p_email),''),updated_at=now() WHERE id=p_id AND status='active';
 IF NOT FOUND THEN RAISE EXCEPTION 'Company unavailable'; END IF;
 INSERT INTO optikrapor.audit_logs(company_id,user_id,event,entity_type,entity_id)
 VALUES(p_id,a.user_id,'company.updated','company',p_id);
END $$;
CREATE OR REPLACE FUNCTION optikrapor.manage_branch(p_company bigint,p_branch bigint,p_code text,p_name text,p_status text)
RETURNS bigint LANGUAGE plpgsql SECURITY DEFINER SET search_path=pg_catalog,optikrapor AS $$
DECLARE a record; out_id bigint;
BEGIN
 SELECT * INTO a FROM optikrapor.auth_claims() LIMIT 1;
 IF a.company_id IS NULL OR a.company_id<>p_company OR NOT EXISTS (
  SELECT 1 FROM optikrapor.user_memberships m JOIN optikrapor.roles r ON r.id=m.role_id
  WHERE m.user_id=a.user_id AND m.company_id=p_company AND m.branch_id IS NULL AND m.is_active AND r.code='company_admin'
 ) THEN RAISE EXCEPTION 'Access denied' USING ERRCODE='42501'; END IF;
 IF length(trim(coalesce(p_code,''))) NOT BETWEEN 1 AND 60 OR length(trim(coalesce(p_name,''))) NOT BETWEEN 2 AND 200
 OR p_status NOT IN ('active','passive') THEN RAISE EXCEPTION 'Invalid fields'; END IF;
 IF p_branch IS NULL THEN
  INSERT INTO optikrapor.branches(company_id,code,name,status) VALUES(p_company,trim(p_code),trim(p_name),p_status) RETURNING id INTO out_id;
 ELSE
  UPDATE optikrapor.branches SET code=trim(p_code),name=trim(p_name),status=p_status,updated_at=now()
  WHERE company_id=p_company AND id=p_branch RETURNING id INTO out_id;
  IF out_id IS NULL THEN RAISE EXCEPTION 'Branch unavailable'; END IF;
 END IF;
 INSERT INTO optikrapor.audit_logs(company_id,user_id,event,entity_type,entity_id)
 VALUES(p_company,a.user_id,CASE WHEN p_branch IS NULL THEN 'branch.created' ELSE 'branch.updated' END,'branch',out_id);
 RETURN out_id;
END $$;
REVOKE ALL ON FUNCTION optikrapor.manage_company(bigint,text,text,text) FROM PUBLIC;
REVOKE ALL ON FUNCTION optikrapor.manage_branch(bigint,bigint,text,text,text) FROM PUBLIC;
GRANT EXECUTE ON FUNCTION optikrapor.manage_company(bigint,text,text,text) TO oprapr;
GRANT EXECUTE ON FUNCTION optikrapor.manage_branch(bigint,bigint,text,text,text) TO oprapr;
INSERT INTO optikrapor.schema_migrations(version,description) VALUES('005','Signed tenant-context admin company and branch changes');
COMMIT;
